BuildNumber ohne SvnAnt

Im vorherigen BlogEintrag “BuildNumber mit SvnAnt” habe ich beschrieben wie mit Hilfe von SvnAnt die Revisionsnummer geholt und eine Proterties Datei geschrieben werden kann. Die build.xml aus der Beschreibung habe ich auf meinem MacBook Pro (Mac OS X Tiger) mit Erfolg laufen lassen. Ein Kollege von mir konnte die Tasks ebenfalls erfolgreich auf seinem Windows XP PC laufen lassen. Auf einem alten Windows 2000 Server konnte die selbe build.xml jedoch nicht erfolgreich durchlaufen werden. Folgende Exception wurde geworfen:

Ant Exception
Ant Exception

Nach dem ich die neuste libjavahl.dll von der Subversion Seite auf den Server kopiert habe, ist beim ausfuehren der build.xml die JVM agestuerzt mit einem Hinweis das eine native Bibliothek den Fehler verursacht hat. Daraufhin habe ich in der build.xml “javahl” auf “false” gesetzt und den neusten Subversion-Client auf dem Server installiert, was leider auch nicht zum Ziel gefuehrt hat.
Da eine schnelle Loesung her musste, habe ich mir folgenden Workaround einfallen lassen um die aktuelle Revisionsnummer auszulesen:

<exec executable="svn"   >
 <arg line="info ${projectName} > ${statusFile}" />
</exec>

Das bewirkt das folgender Befehl auf der Kommandozeile ausgefuehrt wird:

svn info os > status.properties

Der Befehl aus der Kommandozeile funtkioniert wunderbar und leitet die Ausgabe, welche auch die Revisionsnummer enthaelt, in die Datei “status.properties” um. Der Ant-Task fuehrt leider zu einem Fehler:

svn: Fehler beim Ermitteln der Groß-/Kleinschreibung von '>'

Ich habe das “>” Zeichen auf versucht zu escapen mit dem Dollarzeichen, wie bei Ant ueblich, aber leider ohne Erfolg. Auch die Ersetzung durch Unicode-Zeichen hat keinerlei Wirkung gehabt.
Aus dem Grund habe ich eine Batch Datei erstellt mit folgendem Inhalt:

svn info %1 > %2

Diese Batch Datei wird nun mit folgenden Zeilen aus Ant aufgerufen:

 <exec executable="status.bat"   >
 <arg line="${projectName} ${statusFile}"   />
</exec>
 

Der Aufruf funtkioniert und tut genau das was er soll. Anschließend werden in der Ausgabedatei alle “:” durch das “=” Zeichen ersetzt.

 <replaceregexp file="${statusFile}"  match=":"  replace="=" flags="g"   />
 

Somit haben wir wieder eine Propertie-Datei auf die wir mit JSF zugreifen koennen. Das Attribut “flags” hat den Wert “g”, was soviel bedeutet das die Ersetzung in der Datei global geschehen soll.

BuildNumber mit SvnAnt

In dem vorherigen Blogeintrag habe ich beschrieben wie SvnAnt dazu benutzt werden kann die aktuellen Sourcen aus einem Subversion-Server auszuchecken. Vor dem Bauen der Applikation macht es Sinn die aktuelle Revisionsnummer und einen Timestamp in eine Properties Datei zu schreiben. Diese Informationen koennen in einer Web-Applikation im Footer eingeblendet werden. Wenn ein Fehler auftritt, kann der Kunde, im Idealfall, zu der Fehlerbeschreibung die Revisionsnummer und den Timestamp mitschicken. Diese Informationen sind fuer Entwickler bei der Fehlersuche Gold wert.
Der folgende Task in eine build.xml eingefuegt, holt sich die aktuelle Revisionsnummer vom Subversion-Server und schreibt den Wert in die Property “projectStatus.revision”.

<target name="getSVNRevison"  >
 <svn username="${svnUser}"   password="${svnPassword}"  >
 <status path="${projectHome}"   revisionProperty="projectStatus.revision"   />
 </svn>
</target>

Die Variable “projectHome” zeigt auf den Pfad der lokalen Arbeitskopie, der im Idealfall mit einem Ant-Task vorher ausgecheckt wurde.
Der Nachfolgende Task schreibt die Revisionsnummer in eine Properties Datei, erzeugt einen Timestamp und schreibt diesen ebenfalls in eine Prop. Datei.

 <target name="updateBuildNo"   depends="getSVNRevison"  >
 <replaceregexp file="${buildnoFile}"
 match="revision=(.*)"
 replace="revision=${projectStatus.revision}"   />

 <tstamp>
 <format property="buildTimestamp"   pattern="yyyyMMdd-HHmm"   locale="de,DE"   />
 </tstamp>

 <replaceregexp file="${buildnoFile}"
 match="timestamp=(.*)"
 replace="timestamp=${buildTimestamp}"   />

 <echo>Revision: ${projectStatus.revision}</echo>
 <echo>Timestamp: ${buildTimestamp}</echo>
</target>

Auf die Properties Datei kann in einer JSF-Applikation mit der JSF EL zugegriffen werden als Resource-Bundle.

Ant optional Tasks

Die Ant-Task sind in zwei Gruppen aufgeteilt, in die Core-Tasks und in die Optional-Tasks. Eine vollstaendige Auflistung alles Core- und Optional-Task ist in der offiziellen Ant-Docu http://ant.apache.org/manual/ zu finden. Die Optional-Tasks benoetigen alle zusatzliche Bibliotheken wie z.B. ant-apache-oro.jar. Nach der Installtion von Ant auf einem Debian Linux System mit dem Befehl:

apt-get install ant

stehen auf dem System nur die Core-Tasks zur Verfuegung. Wird in einer build.xml ein Optional-Task verwendet wird eine Exception geworfen. Das Problem kann dadurch geloest werden das die optionalen Tasks nachinstalliert werden mit dem Befehl:

apt-get install ant-optional

In dem Archiv das von der offiziellen Homepage http://ant.apache.org/bindownload.cgi heruntergeladen werden kann, sind alle JARs enthalten, auch die fuer die optionalen Tasks.

Ant + Subversion + SvnAnt

SvnAnt ist eine Java-Bibliothek die Ant-Tasks fuer die Vesionsverwaltungs-Software Subversion anbietet. Die Bibliothek kapselt die Moeglichkeiten des Kommandozeilenprogramms “svn” in Ant-Tasks, womit die Kommunikation zwischen Ant und Subversion sehr komfortabel und elegant moeglich ist.
SvnAnt benutzt intern die javahl Bibliothek, ein Java Interface fuer die Subversion API, welche direkt zum Subversion Projekt gehoert. Wenn die Bib. die korrespondierende native Bib. (libsvnant.dll auf Windows) finden kann, dann geschieht die Kommunikation ueber javahl. Wenn die native Implementierung auf dem Betriebssystem nicht gefunden werden kann, gibt es ein FallBack zum Kommandozeilen Interface “svn”. Wenn kein Subversion-Client installiert ist und dementsprechend kein “svn” im PATH eingetragen ist, kann die Verbindung zu Subversion nicht hergestellt werden und es treten Fehler auf.
Es muss also entweder eine native javahl Bibliothek installiert sein oder ein Subversion-Client. Die javahl Bibs werden uebrigens auch im Subclipse Projekt benutzt. Eclipse Benutzer die Subclipse installiert haben, sollten sich hierum keine Sorgen machen. Alle nicht Eclipse Benutzer koennen die Bibliothek von der offiziellen Subversion Homepage runterladen.
SvnAnt kann hier heruntergeladen werden: http://subclipse.tigris.org/svnant.html

In dem entpackten Archiv befindet sich eine vollstaendige Dokumentation im HTML-Format, in dem alle Ant-Tasks mit ihren Attributen beschrieben sind. Die *.jar Dateien aus dem Archiv muessen entweder in die <ANT_HOME>/lib kopiert werden oder die entsprechende build.xml verweist auf die Dateien.
Bei der zweiten Moeglichkeit muss folgender Path in der build.xml eingetragen sein.

<path id="project.classpath"  >
 <fileset dir="../svnant-1.0.0-rc1/lib"  >
 <include name="*.jar"  />
 </fileset>
</path>

Der Pfad zum “svnant-1.0.0-rc1/lib” Verzeichnis muss natuerlich an das jeweilige System angepasst werden.
Der Task wird wie folgt definiert:

 <taskdef name="svn"
 classname="org.tigris.subversion.svnant.SvnTask"
 classpathref="project.classpath"   />

Wenn die *.jar Dateien von SvnAnt in der <ANT_HOME>/lib liegen dann kann das Attribut “classpathref” weggelassen werden. Das auschecken von Sourcecode aus dem Subversion-Server sieht dann so aus:

 <target name="checkout"  >
 <svn username="${svnUser}"   password="${svnPassword}"   javahl="true"  >
 <checkout url="${svnURL}"   destPath="${projectHome}"   />
 </svn>
</target>
 

Mit dem Attribut “javahl” kann hier explizit angegeben werden ob javahl oder das Kommandozeileninterface “svn” zum Gebrauch kommen soll. Standardmaessig hat das Attribut “javahl” den Wert “true”.
Weitere Tasks wie commit, add, delete, copy, createRepository und noch mehr sind in der Dokumentation zu SvnAnt beschrieben.

Ant + Subversion

Subversion ist ein Programm zur Versionskontrolle und der Nachfolger von CVS. Ich habe frueher mit CVS gearbeitet aber seit dem ich Subversion kenne moechte ich nichts mehr von CVS wissen.

Das build-tool ant hat fuer Java Entwickler ungefaehr die gleiche Bedeutung wie “make” fuer die C und C++ Entwickler. Mit ant werden Dateien kopiert, JARs, WARs und EARs gebacken.

Was liegt naeher als die beiden Werkeuzge miteinander zu verbinden. Es gibt verschiedene Moeglichkeiten um mit ant den aktuellen Sourcecode aus einem Subversion-Server auszuchecken. In jedem Fall muss dafuer auf der Maschine auf dem ant laufen soll ein Subversion Client installiert sein.

Auf einem Debian-Linux-System ist das mit folgendem Befehl aus der Kommandozeile erledigt:

apt-get install subversion

Auf einem Mac OS X System empfehle ich die Darwin Ports zu benutzen. Dazu eine Konsole oeffnen und folgenden Befehl absetzen:

port install subversion

Die Windowsbenutzer muessen sich von der Subversion-Homepage ein Programm herunterladen und per Hand installieren. Hier der Link: http://subversion.tigris.org/

Nach der Installation sollte geprueft werden ob der svn-client auch wirklich funktioniert. Der folgende Befehl checkt ein Projekt aus dem Subversion-Server aus:

svn co –-username tom –-password tomtom http://ebtj09.firma.de/svn/fop/trunk zielverzeichnis

Natuerlich muessen die Werte an den eigenen Subversion-Server angepasst werden.
Der selber Aufruf kann auch aus ant heraus abgesetzt werden.

<target name="checkoutBuild"   description="auschecken von Code aus dem Subversion-Server"  >
 <exec executable="svn"  >
 <arg line="co –-username ${svn.username} –-password$ {svn.password} ${svn.projecturl} ${destUrl}"   />
 </exec>
</target>

JasperReports, strech with overflow

In JasperReports hat man oft das Problem das Texte einfach abgeschnitten werden. Wenn ein Textfeld nicht hoch oder breit genug ist, wird abgeschnitten. Das ist das standardverhalten vom Framework.
Wenn sich das Feld dem Textinhalt dynamisch anpassen soll muss das Attribut “stretch with overflow” den Wert “true” haben. In dem grafischen Editor iReport muss man dazu ein Rechtsklick auf das entsprechende Textfeld machen und im Kontextmenue den Eintrag “Properties” auswaehlen. In dem Popup-Fenster der dannach erscheint kann im Karteireiter ganz rechts (“All”) das Attribut gesetzt werden.

Sehr wichtig und weniger intuitiv dabei ist es, das Attribut “stretch type” auf dem Wert “no stretch” zu lassen. Wenn ein anderer stretch type eingestellt ist dann funktioniert das ganze bereits nicht mehr und auf diesen Fehler muss man erstmal kommen 🙂

Das entsprechende Stueck Sourcecode in der *.jrxml Datei dazu sieht wie folgt aus:

<textField isStretchWithOverflow="true"  isBlankWhenNull="false"  evaluationTime="Now"  hyperlinkType="None"   hyperlinkTarget="Self"  >
     <reportElement
            x="138"
            y="112"
            width="386"
            height="14"
            key="textField-12"
            positionType="Float" />
     <box topBorder="None"  topBorderColor="#000000"  leftBorder="None"  leftBorderColor="#000000"  rightBorder="None"  rightBorderColor="#000000"  bottomBorder="None"  bottomBorderColor="#000000" />
     <textElement>
            <font/>
     </textElement>
     <textFieldExpression class="java.lang.String" ><![CDATA[$F{descriptionValue}]]></textFieldExpression>
</textField>

Wenn alles richtig eingestellt ist, kann beliebig viel Text in ein Textfeld eingefuegt werden und dieser wird sogar vollstaendig angezeigt. Alle Element die unter dem Textfeld stehen werden natuerlich dementsprechend nach unten verschoben.

JavaScript Aufruf aus einer ManagedBean heraus mit IceFaces

Mit der Klasse “com.icesoft.faces.context.effects.JavascriptContext” aus der IceFaces 1.6.2 Bibliothek ist es moeglich aus einer ManagedBean heraus JavaScript Aufrufe zu taetigen. Hier folgt ein Beispielaufruf.

JavascriptContext.addJavascriptCall(FacesContext.getCurrentInstance(), "test()");

Der statischen Methode “addJavascriptCall” muss als erster Parameter der aktuelle FacesContext uebergeben werden und als zweiter Parameter die Javascript Methode die aufgerufen werden soll.
Die Methode “test()” befindet sich in einer *.js Datei die im Header des Facelets-Templates eingebunden wird.

N Tomcats auf einer Maschine

Um zwei oder mehr Tomcats auf der selben Maschine laufen zu lassen muessen die Ports in der

<tomcat>/conf/server.xml

angepasst werden, das es sonst zu Portkonflikten kommt. Standardmaessig sind folgende Ports in der server.xml eingetragen.

– server port: 8005
– http port: 8080 redirectPort: 8443
– ajp port: 8009 redirectPort: 8443

Wenn ein zweiter Tomcat im Parallelbetrieb auf der selben Maschine laufen soll, muessen die Ports angepasst werden. Hier ist ein Vorschlag von mir.

– server port: 8006
– http port: 8180 redirectPort: 8444
– ajp port: 8010 redirectPort: 8444

Die server.xml zum ersten Tomcat sieht wie folgt aus.

<Server port="8005"   shutdown="SHUTDOWN"  >

  <Listener className="org.apache.catalina.core.AprLifecycleListener"   SSLEngine="on"   />
  <Listener className="org.apache.catalina.core.JasperListener"   />
  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"   />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"   />

  <GlobalNamingResources>
    <Resource name="UserDatabase"   auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml"   />
  </GlobalNamingResources>

  <Service name="Catalina"  >

    <Connector port="8080"   protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443"   />

    <Connector port="8009"   protocol="AJP/1.3"   redirectPort="8443"   />

    <Engine name="Catalina"   defaultHost="localhost"   jvmRoute="mainworker"  >

       <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"  />

      <Host name="localhost"    appBase="webapps"
            unpackWARs="true"   autoDeploy="true"
            xmlValidation="false"   xmlNamespaceAware="false"  >

      </Host>
    </Engine>
  </Service>
</Server>

Die server.xml fuer den zweiten Tomcat:

<Server port="8006"   shutdown="SHUTDOWN"  >

  <Listener className="org.apache.catalina.core.AprLifecycleListener"   SSLEngine="on"   />
  <Listener className="org.apache.catalina.core.JasperListener"   />
  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"   />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"   />

  <GlobalNamingResources>
    <Resource name="UserDatabase"   auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml"   />
  </GlobalNamingResources>

  <Service name="Catalina"  >

    <Connector port="8180"   protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8444"   />

    <Connector port="8010"   protocol="AJP/1.3"   redirectPort="8444"   />

    <Engine name="Catalina"   defaultHost="localhost"   jvmRoute="tomcat2"  >

      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"  />

      <Host name="localhost"    appBase="webapps"
            unpackWARs="true"   autoDeploy="true"
            xmlValidation="false"   xmlNamespaceAware="false"  >

      </Host>
    </Engine>
  </Service>
</Server>

Nachdem beide server.xml Dateien angepasst und die zwei Tomcats gestartet sind, ist der erste Tomcat unter folgender URL erreichbar:

http://localhost:8080/

Der zweite Tomcat dagegen unter der URL:

http://localhost:8180/

Loadbalancing mit Apache2 + Tomcat 6 + mod_jk

Die Nachfolgende Beschreibung zeigt wie ein Apache2 Webserver als Loadbalancer fuer zwei oder mehr Tomcats zu konfigurieren ist. Die Beschreibung bezieht sich wieder auf einen Linux Debian 4.1.X Server mit 2.6.X Kernel, auf dem ein apache2 Webserver, Tomcat 6.0.16 und Java 5.0 installiert und betriebsbereit ist.

Die folgende Graphik veranschaulicht die Systemarchitektur die aufgebaut werden soll.

34_balancer2
34_balancer2

Wie der Apache2 Webserver mit dem Tomcat ueber das mod_jk Modul verbunden wird, habe ich bereits in einem vorhergehenden Blogeintrag beschrieben. Darauf werde ich hier nicht mehr eingehen.

apache2 + tomcat 6 + mod_jk

Ein Loadbalancer macht nur Sinn wenn mehr als ein Tomcat die gleiche Applikation ausliefert. Der Loadbalancer kann die Last auch zwischen 2 Tomcats verteilen die auf unterschiedlichen Maschinen laufen. Wie zwei oder mehr Tomcats auf der selben Maschine eingerichtet werden, zeigt der folgende Blogeintrag:

N Tomcats auf einer Maschine

Wenn Sie die zwei oberen Blogeintraege gelesen und verstanden haben, dann ist es nur noch ein kleiner Schritt zum Loadbalancer. Als erstes muss die /etc/apache2/workers.properties angepasst werden. Hier ist ein Bespiel:

# Tomcat an Java configuration
#

workers.tomcat_home=/opt/tomcat/
workers.java_home=/opt/java/
ps=/

worker.list=loadbalancer

worker.mainworker.type=ajp13
worker.mainworker.port=8009
worker.mainworker.cachesize=20
worker.mainworker.lbfactor=1
worker.mainworker.host=localhost

worker.tomcat2.type=ajp13
worker.tomcat2.port=8010
worker.tomcat2.cachesize=20
worker.tomcat2.lbfactor=1
worker.tomcat2.host=localhost

worker.loadbalancer.type=lb
worker.loadbalancer.balanced_workers=mainworker,tomcat2
worker.loadbalancer.method=Session

Die worker.list verweist auf den worker “loadbalancer”, welcher vom Typ “lb” (loadbalancing) ist und auf die zwei worker “mainworker” und “tomcat2” verweist. Der lbfactor gibt an wieviel Last ein worker uebernehmen soll. Wenn der mainworker einen lbfactor von 5 haette und der “tomcat2” nur einen von 1, dann wuerde der “mainworker” fuenf mal soviele Anfragen zugewiesen bekommen wie der “tomcat2”.
Eine vollstaendige Dokumentation des workers ist hier zu finden:

http://tomcat.apache.org/connectors-doc/reference/workers.html

Die worker Namen “mainworker” und “tomcat2” muessen natuerlich in den jeweiligen <tomcat>/conf/server.xml Dateien zu finden sein. Der eine Tomcat muss dafuer folgende Zeile in seiner server.xml enthalten:

<Engine name="Catalina"   defaultHost="localhost"   jvmRoute="tomcat2"  >

und der andere dementsprechend die Zeile:

<Engine name="Catalina"   defaultHost="localhost"   jvmRoute="mainworker"  >

Zum Schluss muss noch in der Datei /etc/apache2/sites-enabled/000-default der JkMount-Eintrag auf die gewuenschte Applikation angepasst werden:

JkMount /testApp loadbalancer

Wenn alles korrekt konfiguriert ist kann die Applikation durch folgende URL augerufen werden:

http://localhost/testApp/

Der Apache Webserver wird die Anfrage an eines der zwei Tomcats weiterleiten. Wenn der eine Tomcat runtergefahren wird, ist die Applikation immer noch auf dem zweiten Tomcat verfuegbar. Der Webserver leitet dann alle Anfragen automatisch an den einzig noch verbliebenen Tomcat, so das der Benutzer davon nichts mitkriegt.
Auf diese Art und Weise koennen Applikation ausfallsicherer gemacht werden.

Dynamischer Zugriff auf i18n.properties mit OGNL in Struts 2

In Struts 2 ist es, wie in jedem anderen guten MVC-Framework auch, sehr einfach moeglich Texte zu lokalisieren. Darunter versteht man in Fachkreisen das Auslagern von Texten aus den JSP-Seiten in Propertie-Dateien. Das bietet den Vorteil der Internationalisierbarkeit. Englische Texte koennen in der Datei “package_en.properties” abgelegt werden und deutsche Texte in der Datei “package_de.properties”. Je nachdem welches Locale in der HTTP-Session abgelegt ist greift das Framework entweder auf die deutsche Datei oder auf die englische Datei zu.
Eine Propertie-Datei besteht aus Schluesseln und Werten

firstname=Vorname
lastname=Nachnam

Der Zugriff auf die Texte ist in Struts 2 mit dem folgenden Tag moeglich.

<s:text name="firstname"/>

Der Tag wird, sofern der Schluessel “firstname” in einer Propertie-Datei gefunden wird, durch den Wert “Vorname” ersetzt. Wenn der Schluessel in keiner Propertie-Datei gefunden wird, gibt das Framework den Schluessel als Text aus. Also “firstname”.
Struts 2 benutzt OGNL (Object-Graph-Navigation-Language) um auf die Werte einer Action-Klasse aus einer JSP Seite zu zugreifen. Irgendwann bin ich auf die Idee gekommen mit dynamischen Werten auf die Propertie-Dateien zu zugreifen. Mein erster naiver Versuch sah wie folgt aus.

<s:text name="%{dayOfWeek}"/>

Das hat leider nicht funktioniert, die Seite konnte nicht gerendert werden. Nach einigem Forschen in der OGNL Docu bin ich auf die richtige Loesung gekommen.

<s:text name="%{#attr['dayOfWeek']}"/>

Das funktioniert natuerlich nur wenn der Wert auf dem Stack liegt und die entsprechende Action-Klasse einen Getter “getDayOfWeek()” bereitstellt.
In JSF ist so ein dynamischer Zugriff auf Propertie Dateien aus einer JSP oder XHTML-Seite heraus nicht moeglich. In einer JSF Applikation wuerde man in der ManagedBean auf die Propertie-Datei zugreifen und den Wert ueber eine Variable zur Verfuegung stellen. So das die JSP/XHTML-Seite ueber die Variable Zugriff erlangt.
Das Ergebniss waere das selbe. Jedoch finde ich die Loesung mit OGNL viel eleganter.

Sonderzeichenprobleme in Struts 2

Ich hatte in einer Struts 2 Applikation das Problem das Sonderzeichen, wie öäüÖÄÜß, in einem Texteingabefeld durch Fragezeichen ersetzt wurden. Nachdem das Formular abgeschickt wurde, kamen die Texte aus den Eingabefeldern zwar alle in der Action-Klasse an, jedoch waren alle Sonderzeichen durch Fragezeichen ersetzt.
Das Problem ist relative einfache zu beheben. Die JSP-Dateien sollten alle mit folgender Zeile beginnen:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

Desweiteren sollte in den Formularen das Attribut “acceptcharset” auf den Wert “utf-8” gesetzt werden.

<s:form action="submitForm" method="post" acceptcharset="utf-8">
.
.
.
</s:form>

Das hat bei mir das Problem behoben.

JasperReports, NoClassDefFoundError: org/apache/commons/javaflow/bytecode/Continuable

Neulich habe ich mir JasperReports 2.0.4 und iReport 2.0.4 runtergeladen. Ich habe mir mit iReport einen Report zusammengeklickt und aus iReport heraus den Report compiliert. Nachdem ich die compilierte Datei in mein Eclipse-Projekt kopiert habe und diese in meinem Programm verwenden wollte, erhielt ich die folgende Exception.

java.lang.NoClassDefFoundError: org/apache/commons/javaflow/bytecode/Continuable
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:675)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:1817)
at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:872)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1325)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1204)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)
at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:601)
at org.apache.struts2.views.jasperreports.JasperReportsResult.doExecute(JasperReportsResult.java:240)
at org.apache.struts2.dispatcher.StrutsResultSupport.execute(StrutsResultSupport.java:178)
at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:348)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:253)
at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:50)
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:504)
at org.apache.struts2.dispatcher.FilterDispatcher.doFilter(FilterDispatcher.java:419)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:263)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:584)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:613)

Der Fehler kann sehr leicht behoben werden. iReport 2.0.4 benutzt die Bibliothek commons-javaflow-20060411.jar. Nachdem ich diese Jar-File zu meinen Bibliotheken hinzugefuegt habe, trat der Fehler nicht mehr auf.

Startprobleme mit Eclipse 3.3.1.1 unter Windows

Die Eclipseversion 3.3.1.1 fuer Windows will auf manchen Rechnern einfach nicht so recht starten. Statt dem gewohnten Startbildschirm kommt folgende Fehlermeldung.

7_eclipseErrorStart1
7_eclipseErrorStart1

Dieser Fehler entsteht wenn Eclipse keine aktuelle Java Version finden kann. Eclipse 3.3.1.1 braucht mindestens Java 5.0. Den Fehler kann man sehr leicht beheben in dem man als Startparameter den Pfad zu einer aktuellen Javainstallation mitgibt.
Am besten erstellt man eine Verknuepfung von Eclipse auf seinen Desktop. Rechte Maustaste auf die Verknuepfung und dann im Contextmenu “Eigenschaften” anklicken. Dann muesste folgendes Fenster erscheinen.

8_eclipseStartError2
8_eclipseStartError2

Hier im Textfeld “Ziel” hinter dem Pfad zu eclipse.exe mit dem Parameter “-vm” den Pfad zu einer aktuelle Javainstallation mitgeben. Hier ein Beispiel:

C:\software\eclipse\eclipse.exe -vm C:\Programme\Java\jdk1.5.0_12\bin\javaw.exe

Eclipse startparameter unter Mac OS X

Nachdem Eclipse runtergeladen und entpackt wurde, muss man in das entsprechende Verzeichnis navigieren, am Besten in der Kommandozeile. Hier befindet sich eine Datei mit dem Namen “Eclipse.app”. Mit folgendem Kommando lassen sich die Startparameter edietieren:

emacs Eclipse.app/Contents/MacOS/eclipse.ini

Der Befehl oeffnet die eclipse.ini Datei im Emacs-Editor. Meine eclipse.ini sieht wie folgt aus:

-showsplash
org.eclipse.platform
-vmargs
-Xdock:icon=../Resources/Eclipse.icns
-XstartOnFirstThread
-Xms512m
-Xmx512m
-XX:MaxPermSize=128m
-Dosgi.requiredJavaVersion=1.5
-Dcom.sun.management.jmxremote
-Dorg.eclipse.swt.internal.carbon.smallFonts

Am wichtigsten hierbei ist der Parameter

-XX:MaxPermSize=128m.

Wenn dieser Wert zu niedrig gesetzt ist, verabschiedet sich der Eclipse oft und gerne mit einem OutOfMemmory.

Apache2 + Tomcat 6.0.x + mod_jk 1.2.x

Nachfolgend wird hier beschrieben wie man den apache2 Webserver und den Tomcat 6.0.16 Servletcontainer mit dem mod_jk 1.2.26 verbinden kann. Die Beschreibung bezieht sich auf einen Linux Debian 4.1.X Server mit 2.6.X Kernel, auf dem ein apache2 Webserver, Tomcat 6.0.16 und Java 5.0 installiert und betriebsbereit ist.

Der Tomcat liefert standardmaessig seine Applikationen unter dem Port 8080 aus. Diese Eigenschaft hat Nachteile, weil in vielen Firmennetzen der Port 8080 durch eine Firewall geblockt wird. Der Standard HTTP Port 80 dagegen ist in fast allen Netzen offen.
Der Tomcat laesst sich natuerlich auch so konfigurieren das er auf dem Port 80 horcht. Wenn auf dem gleichen Server aber schon ein Webserver installiert ist, kommt es schnell zu Konflikten. Die eleganteste Loesung besteht darin, den Webserver so zu konfigurieren, dass er bestimmte Domainanfragen an den Tomcat weiterleitet und die Antwort vom Tomcat an den Client weiterschickt.

Um den Apache2 Webserver und den Tomcat Sevletcontainer miteinander zu verheiraten muss man das mod_jk 1.2.26 installieren. Die Entwicklung des mod_jk 2.0 wurde wegen zu komplexer Konfiguration eingestellt, statt dessen wurde die alte Version komplett ueberarbeitet. Die aktuelle Version ist NICHT die 2.0 Serie sondern die mod_jk 1.2.26, welche unter folgender URL zum download bereit steht:

http://tomcat.apache.org/download-connectors.cgi

Da es fuer Debian zu Zeit keine mod_jk binary gibt, muss man sich die Source runter laden und compilieren. Nach dem Download sollte man mit folgenden Befehlen das Packet entpacken und in das native Verzeichnis wechseln.

debian:~# tar -xzvf tomcat-connectors-1.2.26-src.tar.gz
debian:~# chmod -R 755 tomcat-connectors-1.2.26-src
debian:~# cd tomcat-connectors-1.2.26-src/native

Anschliessend muessen fuer die Konfiguration, Kompilierung und Installation folgende drei Befehle ausgefuehrt werden.

debian:~# ./configure --with-apxs=/usr/bin/apxs2
debian:~# make
debian:~# make install

Wenn bei den letzten drei Befehlen Fehler auftreten dann liegt das vielleicht daran das Entwickler-Tools auf dem Server fehlen. Folgender Befehl kann Abhilfe schaffen:

debian:~# apt-get install libtool autoconf gcc apache2-prefork-dev g++

Nach der erfolgreichen Installation des mod_jk Modules muss als naechstes der apache2 Webserver konfiguriert werden. Als erstes muss eine workers.properties Datei erstellt werden.

debian:~# emacs /etc/apache2/workers.properties

Meine workers.properties Datei hat folgenden Inhalt

# Tomcat an Java configuration
#
workers.tomcat_home=/opt/tomcat/
workers.java_home=/opt/java/
ps=/worker.list=mainworker

# Definition for local worker using AJP 1.3
#
worker.mainworker.type=ajp13
worker.mainworker.port=8009
worker.mainworker.cachesize=20

Hier wird der aktuelle Pfad zu tomcat und zu java festgelegt und eine worker Liste beschrieben. In den letzten drei Zeilen wird der mainworker konfiguriert. Der Port 8009 ist ein Standardport fuer den ajp13-Connector von Tomcat. Dieser Wert ist nach dem entpacken von Tomcat standardmaessig in der <tomcat>conf/server.xml eingetragen. Wenn hier in der workers.properties ein anderer Wert eingetragen wird, dann muss die Portnummer in der server.xml vom Tomcat angepasst werden.
Der Name “mainworker” muss in die server.xml noch eingetragen werden.

<Engine name="Catalina"  defaultHost="localhost"  jvmRoute="mainworker"  >

Die eben gezeigte Zeile ist in der server.xml schon vorhanden. Sie muss lediglich um das Attribut jmvRoute=”mainworker” ergaenzt werden. Als naechstes oeffnen wir mit folgendem Befehl die apache2 Konfigurationsdatei:

debian:~# emacs /etc/apache2/apache2.conf

An letzter Stelle muss folgende Zeile hinzugefuegt werden

Include /etc/apache2/sites-enabled/

In dem Verzeichnis /etc/apache2/sites-enables/ befindet sich eine Datei mit dem Namen “000-default”. Die Datei ist in wirklichkeit ein Symlink auf “/etc/apache2/sites-available/default”, aber das soll uns nicht weiter stoeren. Die Datei kann mit jedem beliebigen Texteditor geoeffnet werden und muss um die folgenden Zeilen an erster Stelle ergaenzt werden.

<IfModule !mod_jk.c>
LoadModule jk_module "/usr/lib/apache2/modules/mod_jk.so"
</IfModule>

JkWorkersFile "/etc/apache2/workers.properties"
JkLogFile "/opt/tomcat/logs/mod_jk.log"
JkLogLevel info

In der gleichen Datei befindet sich ein Abschnitt mit VirtualHost, der um die JkMount Eintraege ergaenzt werden muss.
NameVirtualHost *

<VirtualHost *>
ServerAdmin webmaster@localhost
ServerAlias ploin.de www.ploin.de

DocumentRoot /var/www/
..
..
..
..

JkMount /robertReiz mainworker
JkMount /robertReiz/* mainworker

</VirtualHost>

Die letzten zwei Zeilen im VirtualHost Abschnitt teilen den Webserver mit das er alle Anfragen die mit robertReiz beginnen an den mainworker weiter leiten soll.

Nun muessen nur noch der Tomcat und der apche2 Webserver neu gestartet werden. Damit ist die Konfiguration abgeschlossen.

AJAX

Note for me. AJAX Code.

 var http;

 function keepSessionOpen(){
    window.setTimeout('keepSessionOpen()', 1200000); // 1 200 000 = every 20 minutes
    var myurl = "#{statusBean.link}/page/status.xhtml";
    http = http.open("POST", myurl, true);
    http.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
    http.setRequestHeader("Connection", "Keep-Alive");
    http.onreadystatechange = useHttpResponse;
    http.send(null);
 }

 function getHTTPObject() {
    if (typeof XMLHttpRequest != 'undefined') {
        return new XMLHttpRequest();
    }
    try {
        return new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
        try {
            return new ActiveXObject("Microsoft.XMLHTTP");
        } catch (e) {
            alert(e);
        }
    }
    return false;
 }

function useHttpResponse() {
    if (http.readyState == 4 && this.status != 200) {
        alert(this.status);
    }
}

Archetype: RichFaces 4.0.0.M1 + Spring 3.0.4.RELEASE + Hibernate 3.3.0

This maven2 archetype contains a little sample web application with this Frameworks:

  • Spring 3.0.4.RELEASE Framework
  • Servlet-API 2.5
  • JSF 2.0 (mojarra 2.0.2)
  • RichFaces 4.0.0.M1
  • ploinFaces 1.6
  • ploinMailFactory 1.3.1
  • Hibernate 3.3.0
  • TestNG 5.8
  • Log4J 1.2.15
  • HSQLDB 1.8.0.7

The configuration is annotation-driven. It is deployed on the PLOIN Repository-Serve

http://www.ploin-m2.de/nexus/content/groups/public/

you can create a project from the archetype with the following command:

mvn archetype:generate -DarchetypeGroupId=org.ploin.archetype -DarchetypeArtifactId=tempSpringRichHibernate -DarchetypeVersion=1.7.1 -DarchetypeRepository=http://www.ploin-m2.de/nexus/content/groups/public/ -DgroupId=org.ploin -DartifactId=demoSpringRichHibernate

The created project is a very simple web-application with a login mask and 2 xhtml-sites. I have tested the app on a tomcat 6.0.20 and Java 1.6 on Mac OS X Snow Leopard.

rich-faces-login
rich-faces-login

You can login with the username “admin” and the password “admin”.

After the creation the app is running with the HypersoniceSQL DBMS. But it is very easy to switch to MySQL or Oracle. I put the drivers for MySQL and Oracle as a comment in the pom.xml. So you just need to comment in the right lines in the pom.xml.

Archetype: JSF 2.0 + Spring 3.0.4.RELEASE + Hibernate 3.3.0

This maven2 archetype contains a little sample web application with this Frameworks:

  • Spring 3.0.4.RELEASE Framework
  • Servlet-API 2.5
  • JSF 2.0 (mojarra 2.0.2)
  • ploinFaces 1.6
  • ploinMailFactory 1.3.1
  • Hibernate 3.3.0
  • TestNG 5.8
  • Log4J 1.2.15
  • HSQLDB 1.8.0.7

The configuration is annotation-driven. It is deployed on the PLOIN Repository-Server

http://www.ploin-m2.de/nexus/content/groups/public/

you can create a project from the archetype with the following command:

mvn archetype:generate -DarchetypeGroupId=org.ploin.archetype -DarchetypeArtifactId=tempJsf2Spring3Hibernate3 -DarchetypeVersion=1.0 -DarchetypeRepository=http://www.ploin-m2.de/nexus/content/groups/public/ -DgroupId=org.ploin -DartifactId=demoJsfSpringHibernate

The created project is a very simple web-application with a login mask and 2 xhtml-sites. I have tested the app on a tomcat 6.0.20 and Java 1.6 on Mac OS X Snow Leopard.

You can login with the username “admin” and the password “admin”.

After the creation the app is running with the HypersoniceSQL DBMS. But it is very easy to switch to MySQL or Oracle. I put the drivers for MySQL and Oracle as a comment in the pom.xml. So you just need to comment in the right lines in the pom.xml.

Useful M2 – Repos

Here are some useful Maven2 Repositorys listed.

EclipseLink:

<repository>
  <id>EclipseLink Repo</id>
  <url>http://www.eclipse.org/downloads/download.php?r=1&nf=1&file=/rt/eclipselink/maven.repo</url>
</repository>

PLOIN Repository, containing ploinFaces and ploinMailFacotry:

<repository>
  <id>ploinPublic</id>
  <name>ploinPublic</name>
  <url>http://ploin-m2.de/nexus/content/groups/public/</url>
</repository>

JSF 2.0, java.net:

<repository>
  <id>maven2-repository.dev.java.net</id>
  <name>Java.net Repository for Maven 2</name>
  <url>http://download.java.net/maven/2/</url>
  <layout>default</layout>
</repository>

Ibiblio, mirror of M2:

<repository>
 <id>ibiblio.org</id>
 <name>ibiblio Repository for Maven 2</name>
 <url>http://mirrors.ibiblio.org/pub/mirrors/maven2/</url>
 <layout>default</layout>
 </repository>

Codehaus

<repository>
 <id>repository.codehaus.org</id>
 <name>Codehaus Repository</name>
 <url>http://repository.codehaus.org/</url>
 </repository>

Selenium:

<repository>
 <id>openqa-releases</id>
 <name>OpenQA Releases</name>
 <url>http://archiva.openqa.org/repository/releases/</url>
 <releases>
 <enabled>true</enabled>
 </releases>
 <snapshots>
 <enabled>false</enabled>
 </snapshots>
 </repository>
 <repository>
 <id>openqa-snapshots</id>
 <name>OpenQA Snapshots</name>
 <url>http://archiva.openqa.org/repository/snapshots/</url>
 <releases>
 <enabled>false</enabled>
 </releases>
 <snapshots>
 <enabled>true</enabled>
 </snapshots>
 </repository>
 <repository>
 <id>openqa-thirdparty</id>
 <name>OpenQA Third Party</name>
 <url>http://archiva.openqa.org/repository/thirdparty/</url>
 <releases>
 <enabled>true</enabled>
 </releases>
 <snapshots>
 <enabled>false</enabled>
 </snapshots>
 </repository>

Spring-Framework:

<repository>
 <id>springsource maven repo</id>
 <name>springsource maven repo</name>
 <url>http://maven.springframework.org/milestone</url>
 </repository>

 

JBoss:

<repository>
 <id>repository.jboss.org</id>
 <name>Jboss Repository for Maven</name>
 <url>http://repository.jboss.org/maven2/</url>
 </repository>
 <repository>
 <id>snapshots.jboss.org</id>
 <name>Jboss Snapshots Repository for Maven</name>
 <url>http://snapshots.jboss.org/maven2/</url>
 <snapshots>
 </snapshots>
 </repository>