Geschrieben von everflux am August 23rd, 2011
Bei Caliper handelt es sich um ein Framework um Mikrobenchmarks für Java Programme durchzuführen. Caliper ist bei Google code gehostet – http://code.google.com/p/caliper/ – und steht unter der Apache 2 Lizenz, kann somit sehr frei verwendet werden.
Caliper verfolgt einen ähnlichen Ansatz wie JUnit, Methoden müssen mit „time“ als Prefix benannt werden, und einen Parameter vom Typ int entgegennehmen um dann ausgeführt zu werden. Dieser Parameter gibt an, wie viele Iterationen der zu messenden Methode durchzuführen sind.
Leider ist Caliper bisher noch nicht in einer Version 1.0 released worden, daher bleibt nur selber bauen. Derzeit ist das jedoch auch nicht ganz einfach: Caliper haengt von Google Guava ab, nutzt in der svn-trunk Version dazu auch bereits Features von Guava r10, was auch noch nicht released ist. Also auch hier: Selber bauen, und die Abhängigkeit in Caliper korrigieren. Mein favorisiertes Build Tool ist in diesem Fall maven.
Möchte man noch während des Benchmarks die Speichernutzung analysieren, so bietet Caliper dies auch an – über einen Java Agent der von dem Google Projekt java-allocation-instrumenter (http://code.google.com/p/java-allocation-instrumenter/, Apache 2 Lizenz) bereitgestellt wird. (Leider ist hier derzeit der Maven Build nicht so konfiguriert, dass als Artefakt ein nutzbarer Java Agent erzeugt wird. Dies ist im Ant basierten Build in Ordnung, und kann mit einem kleinen Patch der Maven Konfiguration auch behoben werden.)
Der letzte Wehrmutstropfen bleibt nun, dass Caliper gerne eine Environment Variable, statt bspw. einem System Property, hätte, um den zu nutzenden Java-Agent zu spezifizieren – diese lässt sich bei Ausführung als Script zwar einfach setzten, jedoch aus einer Java Anwendung heraus eigentlich nicht. Dazu später mehr.) Weiterlesen »
Geschrieben von everflux am Februar 17th, 2011
Bei der Umstellung von Jetty 6 zu Jetty 7 gab es (wie bereits geschildert) das eine oder andere an Überraschungsmomenten. So auch bei einem länger laufenden Request ( Fileupload anschließendes Parsen und Datenbank Updates die sich einige Minuten hinziehen können).
Die saubere Lösung wäre hier natürlich dem Nutzer eine Art Fortschritts-Anzeige zu präsentieren. Da die Funktion jedoch so bereits getestet ist, und auch kein Umbau geplant war, sollte es so bleiben. Lediglich Jetty hat hier (mal wieder) einen Strich durch die Rechnung gemacht: Geschlossene Verbindungen die mit org.eclipse.jetty.io.EofException und vielen hässlichen Stacktraces kommentiert wurden. Erst hatte ich die Applikation in Verdacht.
Dann den Browser – macht der Browser vielleicht die Verbindung zu, wird der Socket nur solange wie „keep-alive“ erlaubt ist offen gehalten? Mit etwas wireshark / tcpdump konnte ich dann beweisen: Es war Jetty. Der Server schloss die Verbindung bevor der Prozess fertig war.
Zum Glück kann man aber den idle Timeout von Jetty konfigurieren, das ist die Zeit, in der eine Verbindung ohne Fortschritt fortbestehen darf. (Fortschritt wäre hier ein gesendetes oder empfangenes Byte.) Hier kann man noch gut in die Falle tappen, dass die Zeit in Milisekunden angegeben werden muss – lediglich der verdeckte Hinweis, dass der Wert „grob gesagt“ in den Parameter für Socket.setSoTimeout(int)
übersetzt wird, bringt einen hier auf die Spur.
Für das Jetty Maven Plugin sieht das dann so aus:
<configuration>
<connectors>
<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<port>8080</port>
<maxIdleTime>600000</maxIdleTime> <!-- 10 minutes in milliseconds! -->
<lowResourcesMaxIdleTime>600000</lowResourcesMaxIdleTime>
</connector>
</connectors>
</configuration>
Geschrieben von everflux am Januar 28th, 2011
Es hat nur wenige Monate gedauert, aber dann konnte ich endlich einen besonders nervigen Fehler finden. Ich verwende Maven (wie fast immer) als Buildsystem und habe ein Projekt, dass Eclipse BIRT verwendet.
BIRT nutzt die Eclipse OSGi Plattform und daher werden beim Start einige Bilbiotheken benötigt. Nun gab es das Problem, dass dies im Tomcat nach einer kleinen Anpassung des Classpath prima funktionierte – nicht jedoch wenn ich das Maven Jetty Plugin verwendet habe. Trotz lt. Dokumentation korrekter Konfiguration über webAppConfig und extraClasspath Elemente.
Die Lösung war dann schließlich nicht mehr das maven-jetty-plugin in Version 6.1.2 sondern das – Achtung – jetty-maven-plugin in Version 7.2.1.v20101111 (die Versionnummer ist kein Witz) zu verwenden. Offenbar ein Jetty Bug – anders kann ich es mir nicht erklären.
Und so sieht dann die vollständige Konfiguration aus, die bei mir dann endlich auch zum Testen schnell und komfortabel funktioniert:
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>7.2.1.v20101111</version>
<configuration>
<webAppConfig>
<extraClasspath>${BIRT_HOME}/lib/engineapi.jar;${BIRT_HOME}/lib/coreapi.jar; \
${BIRT_HOME}/lib/modelapi.jar;${BIRT_HOME}/lib/org.apache.commons.codec_1.3.0.v20100518-1140.jar; \
${BIRT_HOME}/lib/scriptapi.jar</extraClasspath>
</webAppConfig>
</configuration>
</plugin>
Geschrieben von everflux am Januar 22nd, 2011
Entwickelt man mit Jetty als Servlet Container, so fällt der im Vergleich zu Glassfish relativ hohe Aufwand für Re-Deployments auf: Startet man Jetty per „mvn jetty:run“ für jedes Deployment erneut, so dauert der Neustart erst mal relativ lange, dazu geht noch die gerade aktive Session verloren. So muss man sich gegebenenfalls nach jeder Änderung bzw. jedem Restart erneut anmelden.
Das kann man relativ einfach ändern: Jetty verfügt über die Möglichkeit die Session zu persistieren – dazu müssen natürlich Session Objekte serialisierbar sein, aber das sollten diese ja sowieso sein. (Stichwort „Session migration“ und „Clustering“)
Leider findet sich auf der Jetty Homepage lediglich eine Anleitung für Jetty 6 – Jetty 7 wird nun von Eclipse weiter entwickelt und damit gehen einige Änderungen einher, für die ich hier eine Beispielkonfiguration habe:
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>7.2.1.v20101111</version>
<configuration>
<webAppConfig>
<sessionHandler implementation="org.eclipse.jetty.server.session.SessionHandler">
<sessionManager implementation="org.eclipse.jetty.server.session.HashSessionManager">
<storeDirectory>${basedir}/target/sessions/</storeDirectory>
</sessionManager>
</sessionHandler>
<contextPath>/${project.artifactId}</contextPath>
</webAppConfig>
<!--
<reload>automatic</reload>
<scanIntervalSeconds>2</scanIntervalSeconds>
<scanTargets>
<scanTarget>target/classes/</scanTarget>
</scanTargets>-->
</configuration>
</plugin>
Mit dieser Einstellung werden die Session Daten in dem Order „target/sessions“ persistiert, und man kann bei einem Neustart dort weitermachen, wo man aufgehört hat.
Geschrieben von everflux am Januar 7th, 2011
Verwendet man Maven für ein Java JSP Projekt und Netbeans als IDE, so koennen erstaunliche Fehler entstehen: Um mit Servlets zu arbeiten, wird man im Maven die Abhängigkeit auf die Servlet API deklarieren. Da der Webcontainer sich später um die Implementierung der Servlets – und auch das Kompilieren von JSP Seiten – kümmert, gibt man als Scope „provided“ an.
Beispielsweise so:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
Damit funktioniert die Entwicklung dann auch prinzipiell – bis auf rote Hinweise und Fehlermeldungen im Netbeans JSP Editor:
„package javax.servlet.jsp does not exist“
(cannot find symbol)
und so weiter und so fort. Bei allen JSP Direktiven, JSP Deklarationen etc. gibt es einen Hinweis darauf, dass Netbeans da etwas im Classpath fehlt. Und Netbeans hat dabei auch Recht – wenn man die JSP API nicht ebenfalls als Projekt Abhängigkeit deklariert. Hier hilft also ein kleiner Zusatz in der Maven pom.xml, der so aussehen könnte:
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
Hier ist die JSP Version 2.1 passend zur Servlet API 2.5 gewählt. Anschließend einmal „clean and build“ in Netbeans geklickt, und die „package javax.servlet.jsp does not exist“ Fehler sind behoben.
Geschrieben von everflux am Dezember 17th, 2010
Ich wollte eigentlich nur etwas ganz simples: Continuous Deployment. Das ist der neueste Trend nach Continous Integration habe ich mir sagen lassen. Und gerade wenn man in einem Team arbeitet ist es schon vorteilhaft, wenn man einen stabilen Build staendig deployt hat.
Hudson ist mein bevorzugter Buildserver (auch wenn Bamboo wirklich ansprechender ist, aber eben auch eine Ecke teurer und nicht OpenSource) – und es gibt auch ein Plugin fuer Hudson, mit dem man ein Deployment anstarten kann: http://wiki.hudson-ci.org/display/HUDSON/Deploy+Plugin
Leider funktioniert das bei dem Glassfish nicht, wenn Hudson nicht auf dem selben Server läuft, wie der Glassfish. (Das sollte/dürfte der Regelfall sein.)
Weiterlesen »
Geschrieben von everflux am Dezember 15th, 2010
Updates haben nicht immer nur gutes – manchmal gibt es auch neue Fehler oder Animositäten. So auch bei Maven:
Seit dem Maven Ressource Plugin Version 2.4.x wurden einige Ressource Dateien nicht mehr korrekt gefiltert. Das Filtern von Ressourcen kann man z.B. dazu verwenden, um automatisch Build oder Versionsnummern einzufügen.
Die Konfiguration dafür ist einfach:
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>*.properties</include>
</includes>
</resource>
</resources>
Schon kann man z.B. in der version.properties dann revision = ${buildNumber} eintragen, und erhält nach jedem Build die inkrementierte Build-Nummer. (Vom Maven Buildnumber Plugin)
Nur funktionierte es plötzlich nicht mehr. Genauer gesagt, es funktionierte nicht mehr bei allen Dateien. Die Ursache (nach langem Suchen): Das Zeichen „@“ ist als neuer Delimiter hinzugefügt worden. Enthielt jetzt eine der zu filternden Dateien ein „@“ eben als solches, und nicht als Teil eines Patterns, wurde das Filtern abgebrochen. Eine Fehlermeldung oder Warnung habe ich nicht gesehen – mag aber sein, dass Maven die irgendwo mal ausgespruckt hat.
Abhilfe schafft hier die folgende explizite Konfiguration des Maven Resource Plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4.3</version>
<configuration>
<useDefaultDelimiters>false</useDefaultDelimiters>
<delimiters>
<delimiter>${*}</delimiter>
</delimiters>
</configuration>
</plugin>
Damit wird das das alte Verhalten des Plugins wieder hergestellt, und „@“ Zeichen als Trennzeichen für Ersetzungen ignoriert.
Vielleicht gibt es auch mal einen offiziellen Code fix – Maven Bug: http://jira.codehaus.org/browse/MRESOURCES-117
Geschrieben von everflux am März 17th, 2010
Hudson und Maven sind an und für sich ein gutes Gespann… außer es funktioniert mal nicht.
Ausser der Meldung „Socket Timeout“ kamen nicht so viele Hinweise:
[application] $ /usr/lib/jvm/java-6-sun/bin/java -Dmaven.repo.local=/home/hudson/maven-repository/ -Xms512m
-Xmx1024m -cp /home/hudson/hudson/plugins/maven-plugin/WEB-INF/lib/maven-agent-1.351.jar:
/home/hudson/maven/boot/classworlds-1.1.jar hudson.maven.agent.Main
/home/hudson/maven /home/hudson/hudson/war/WEB-INF/lib/remoting-1.351.jar
/home/hudson/hudson/plugins/maven-plugin/WEB-INF/lib/maven-interceptor-1.351.jar 57590
/home/hudson/hudson/plugins/maven-plugin/WEB-INF/lib/maven2.1-interceptor-1.2.jar
ERROR: Aborted Maven execution for InterruptedIOException
java.net.SocketTimeoutException: Accept timed out
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:390)
at java.net.ServerSocket.implAccept(ServerSocket.java:453)
at java.net.ServerSocket.accept(ServerSocket.java:421)
at hudson.maven.MavenProcessFactory$SocketHandler$AcceptorImpl.accept(MavenProcessFactory.java:167)
at hudson.maven.MavenProcessFactory.newProcess(MavenProcessFactory.java:202)
at hudson.maven.ProcessCache.get(ProcessCache.java:231)
at hudson.maven.MavenModuleSetBuild$RunnerImpl.doRun(MavenModuleSetBuild.java:455)
at hudson.model.AbstractBuild$AbstractRunner.run(AbstractBuild.java:416)
at hudson.model.Run.run(Run.java:1240)
at hudson.maven.MavenModuleSetBuild.run(MavenModuleSetBuild.java:304)
at hudson.model.ResourceController.execute(ResourceController.java:88)
at hudson.model.Executor.run(Executor.java:122)
Finished: ABORTED
Aber auch eine Lösung konnte ich für das Hudson/Maven Problem finden: Deaktivieren von ipv6 brachte die Lösung. Ob es wirklich am ipv6 liegt, oder was dann der tatsächliche Grund war, habe ich nicht weiter untersucht.
Das sonst bei Java Anwendungen gerne verwendete -Djava.net.preferIPv4Stack=true
half in meinem Fall jedenfalls nicht.
Geschrieben von everflux am Januar 14th, 2010
Netbeans hat einen sehr guten Support für Maven, Maven Projekte werden genauso gut behandelt, wie die ant basierten nativen Netbeans Projekte.
Doch an einer Stelle hakt es etwas: Moechte von Maven dependencies auch den Source Code bzw. JavaDoc zur Verfuegung haben, reicht es nicht, wenn man (wie üblich) ueber die Maven Properties
<downloadSources>true</downloadSources>
und <downloadJavadocs>true</downloadJavadocs>
den Download aktiviert. Weiterlesen »
Geschrieben von everflux am August 25th, 2009
Netbeans hat – zum Glück – neuerdings Maven Support. Das macht insbesondere die Anpassung des Build Prozesses wesentlich einfacher. Dazu kommt, dass Maven Kenntnisse nicht nur bei Netbeans Usern verbreitet sind, und so bessere Interoperabilität erzielt wird.
Hat man jedoch kein Maven Projekt, sondern das „klassische“ ant basierte Chaos Buildsystem, können Anpassungen schonmal komplizierter werden.
In diesem Fall ging es darum, dass mit Netbeans /ant produzierte Artefakte als einzelne JAR Datei verteilbar sein sollten. D.h. alle Bibliotheken bzw. Library JAR Files sollten in einem einzelnen, ausführbaren JAR landen. Weiterlesen »
Neue Kommentare