Archiv: Web Entwicklung

Host vs. Cloud

27 September 2016

Wer sich mit dem Thema Cloudcomputing beschäftigt, der stößt unweigerlich auf das Thema Ausfallsicherheit. Bei Host-Systemen wird mit sehr aufwendigem und teurem Engineering Ausfallsicherheit durch "self-healing", Redundanz und Hot-Plug-Fähigkeiten erzielt. Fällt ein Netzteil aus, wird durch ein oder mehrere redundante Netzteile die zum Betrieb notwendige Stromversorgung weiter aufrecht erhalten. Sobald ein Ersatzteil verfügbar ist, kann das defekte Netzteil dann ohne Betriebsunterbrechung ersetzt werden. Skalierung erfolgt durch sehr leistungsfähige Komponenten, wird mehr Durchsatz benötigt so kann bei Mainframes zusätzliche Kapazität freigeschaltet werden ("on demand").

In der Cloud ist es genau andersherum: Jeder einzelne Rechner bringt eine eher geringe Verfügbarkeit mit sich, mehr Leistung auf den einzelnen Knoten ist ebenfalls nur sehr begrenzt verfügbar. Ausfallsicherheit wird durch extreme Verteilung - bis hin über den ganzen Globus - und Vermeidung von Single Points of Failure erzielt. Skalierung analog. Selbst der Ausfall ganzer Rechenzentren oder gar die Infrastruktur eines Kontinents ist damit theoretisch verschmerzbar.

Klassische Enterprise IT bewegt sich meist zwischen den beiden extremen: Die einzelnen Rechner bestehen aus hochwertigen Komponenten, dank Virtualisierung lassen sich Hardwaremigrationen durchführen um bei Ausfall oder Wartung von Servern den Betrieb weiter zu gewährleisten.

Jedes Szenario hat eigene Vor- und Nachteile, am meisten fällt der finanzielle Aspekt ins Auge. Host/Mainframe ist sehr teuer in der Anschaffung, Betrieb/Wartung und erfordert spezielle Fachkräfte, die sich im Vergleich zu weniger spezialisierten Personen entsprechend fürstlich bezahlen lassen. Auch lässt der eiserne Griff der Anbieter einen Wechsel auf andere Plattformen sich oft nur schwer wirtschaftlich darstellen.

Allen ist jedoch eins gemeinsam: Totalausfälle sind zu vermeiden und durch entsprechende Massnahmen zumindest eingeschränkter Betrieb aufrecht zu erhalten. (Zum Beispiel als Read-Only.)

Was man nie zu sehen bekommen sollte, ist daher so etwas wie hier bei dem Buchungssystem der Lufthansa

lufthansa_down

Middleman and Google AMP (accelerated mobile pages)

10 June 2016

Mobile growth is a driver for many technologies: Responsive design, HTTP/2, HTML5 replacing Flash. Facebook started with an own format for optimized mobile delivery. This is not only beneficial to users: If a page is displayed fast, ads are visible before the user clicks away, as well.

Google followed the approach of a custom format, called Accelerated Mobile Pages (Google AMP). Instead of choosing a completely different container, like XML, proven technologies were used: HTML, JavaScript and schema.org JSON notation. By using a JavaScript based runtime to implement functions like delayed loading of non-essential assets and inlining CSS, the initial transmission size of the page can be reduced.

While Wordpress got support for generating AMP content by a plugin, other CMS applications seem to be lacking. Especially when using static site generators it can be challenging to generate multiple variants from the same content. I like static site generators for several reasons:

  • Can be served from a low-grade webserver without special requirements
  • Really, really fast page serving
  • Easy to cache / integrate CDN
  • Low attack surface, easy to secure

I used middleman in several projects, so far I am quite happy with it. Thanks to integrated asciidoctor support it was even possible to use a common source for web pages as well as print documents, distributed by other channels.

When facing the desire to provide Google Accelerated Mobile Pages (AMP) using the existing middleman setup along with the existing content I noticed the shortcomings of HTML or asciidoc based page templates. Nevertheless I went ahead and use some customizations (some would call it hacks) to achieve my goal. I prototyped it for trion.de and you can see the AMP result on https://www.trion.de/amp/

The implementation uses the latest middleman 4 and the targets plugin to have multiple variants as build targets. To ensure that the AMP links to not point to the non-AMP version by accident a link_prefix and deployment of AMP to a subdirectory is used. Another option would have been to use a subdomain. Of course the AMP version uses a different layout which includes the AMP engine JavaScript and required markup and meta data for the AMP pages.

 

# Build Targets
# https://github.com/middlemac/middleman-targets
config[:targets] = {
  default: {
    build_dir: "build",
    layout: "layout",
    link_prefix: nil,
    features:
    {
    }
  },
  amp: {
    build_dir: "build/amp",
    layout: "amp",
    link_prefix: "/amp",
    features:
    {
    }
  }
}
In order to be able to reuse the existing content, some global search-and-replace is applied as part of the template.

 

<% content = yield %>
<%
content.gsub!("<img", "<amp-img")
content.gsub!("<iframe", "<amp-iframe")
content.gsub!("</img", "</amp-img")
content.gsub!("</iframe", "</amp-iframe")
%>
<%= content %>
 

It is now obvious why this can be called a hack instead of an engineered solution. A better approach would be possible if the source data for the pages is provided in a more strcutured format like JSON or YAML. Both are supported by middleman and are a good choice for content that follows a well defined structure. (A good example is the trainings catalogue on trion.de/schulung/schulungen-coaching-training.html)

Google AMP (Accelerated mobile pages)

27 February 2016

Google hat das AMP (Accelerated Mobile Pages) Projekt initiiert, um speziell für mobile Endgräte bei mittelmäßiger Datenverbindung Inhalte schneller ausliefern zu können. Das hat sicherlich nicht zuletzt den Hintergrund, dass dann auch mehr Werbung konsumiert wird...

Das AMP Format ist im wesentlichen ein speziell formatiertes HTML Dokument mit JavaScript, dass genutzt wird um Dinge wie lazy-loading und Analytics zu unterstützen.

Nutzt man Wordpress als Blogging Software, so steht dafür jetzt ein offizielles Plugin zur Verfügung, mit dem die Inhalte auch im AMP Format ausgegeben werden. Aktiviert man das Plugin, so sieht man bereits nach kurzer Zeit in der Search Console (ehemals Webmaster Tools), dass Google die Inhalte findet und auch indiziert.

Ich habe das für dieses Blog testweise mal gemacht, ich bin gespannt, wie sich AMP dann auswirkt.

Netbeans - Choose your color!

7 March 2015

As I regularly test different versions of Netbeans as part of the community acceptance program (NetCAT) and for my own fun and benefit I sometimes struggle to start of the right version: Usually the release version is the right one to go. During NetCAT the beta version needs to be tested and when new features are so promising that you want to run the nightly, you go with that.

I came up with a simple solution to never  launch the wrong edition: Differently colored Netbeans icons. This is how my Gnome launcher looks:

netbeans-choose

Easy to tell that red is the nightly, without looking at the icon text! If you want that for yourself, you can get the icons here:

netbeans-dev netbeans-beta

The icons are created using Gimp and just rotating the colors, so it's a little hacky but does the trick.

In Gnome you can use the application 'alacarte' (or 'main menu' if you run the english locale) to customize your launchers. Just change the icon:

alacarte

Netbeans, Vagrant und remote PHP Debugging mit xdebug

14 February 2015

Vielleicht hilft dieser Tipp dem einen oder anderen weiter, der gerne die Netbeans IDE zur PHP Entwicklung verwendet und auch Vagrant nutzt: Wenn man mit Vagrant arbeitet, so werden die lokalen Dateien in der virtuellen Maschine gemounted. Für Netbeans konfiguriert man daher "lokalen Webserver" als Umgebung.
Die Konfiguration von xdebug sieht dann am einfachsten so aus: [xdebug]
xdebug.remote_enable = 1
xdebug.remote_connect_back = 1
;xdebug.remote_autostart = 1
xdebug.remote_handler=dbgp
Hier wird xdebug angewiesen, sich zum Aufrufer zurück zu verbinden - die IP wird aus dem Request genommen. Das passt in der Regel, wenn man innerhalb von Vagrant nicht noch wilde Sachen (Proxy) macht.
Was leider nicht passt: Die Pfade. Netbeans weißt xdebug für Breakpoints an, welche Datei - inkl. Pfad - an welcher Stelle einen Breakpoint erhalten soll. Die Ordnerstruktur ist innerhalb der virtuellen Maschine höchstwahrscheinlich anders, als auf dem Host-System.
Hierzu gibt man innerhalb von Netbeans noch ein Pfad-Mapping an: Projekt Konfiguration, "Run Configuration", "Advanced".
Nun waehlt man aus, wo man innerhalb der Vagrant bzw. VirtualBox Umbebung den Projekt Ordner eingebunden hat. In meinem Beispiel ist das /var/www/localhost

Anschließend kann man den Netbeans Debugger verwenden.
Möchte man spezielle Requests, wie z.B. PUT, mittels curl aufrufen kann man dies auch ganz einfach machen, in dem man den Xdebug Trigger als Parameter anhängt: curl -X PUT -d '{}' http://localhost:8080/rest/endpoint.php/duplicates\?XDEBUG_SESSION_START\=netbeans-xdebug

Ein Screenshot der Netbeans Konfiguration als Referenz: path-mapping

Middleman live reload mit Vagrant

31 January 2015

Middleman ist ein static site generator der sich einiges von Ruby-On-Rails leiht, aber eben nur statische Seiten generiert. In vielen Anwendungsfällen ist das auch genau das richtige.

Um die Web-Entwicklung zu erleichtern - vor allem auch mit mobilen Geräten - gibt es das vorzügliche Werkzeug "livereload". Damit wird im Browser ein reload ausgelöst, wenn sich die Quellen geändert haben. Das spart Zeit und man muss nicht dauernd aus dem Texteditor oder der IDE raus um im Browser einen Reload manuell auszulösen. Zur Integration gibt es zum einen native Browser Extensions, zum anderen kann dies auch über ein JavaScript integriert werden.
Hinter den Kulissen nutzt livereload einen Websocket (ggf. mit Polyfill über Flash) um  den Client dann zu informieren.

Was liegt nun näher, als middleman als static site generator mit livereload zu verbinden. Am besten das ganze noch mit vagrant, so dass man eine isolierte Entwicklungsumgebung hat. Da vagrant mit VirtualBox arbeitet, kommt etwas mehr Komplexität auf einen zu. Der middleman läuft nun nicht mehr auf dem physischen Rechner sondern virtualisiert - damit hat er auch eine andere IP. Einzelne Ports koennen in die virtuelle vagrant Maschine reingereicht werden, das ist für das livereload wegen des Websockets schon mal wichtig. Dazu muss in der vagrant Konfiguration (Vagrantfile) folgender Eintrag vorhanden sein: #middleman live reload port
config.vm.network :forwarded_port, host: 35729, guest: 35729

Jetzt muss middleman noch konfiguriert werden, dass es auch livereload verwendet:
Im Gemfile für middleman: gem 'middleman-livereload'

In der middleman Konfigurationsdatei muss nun das livereload konfiguriert werden. Hier ist nun die Besonderheit: Das Livereload Plugin differenziert nicht zwischen der Host-Angabe um das Interface zu bestimmen an den der Websocket Server gebunden wird, und der URL die für den Zugriff auf den livereload Server verwendet wird. Gibt man hier "127.0.0.1" an, bindet er nur an das lokale Interface in der virtuellen Maschine. Gleiches für "localhost". Gibt man die externe IP des Hosts an, dann findet das rack-livereload das Interface nicht.

Da hilft als letztes nur noch das "Universalbinding" - zum Glück ist das auch vom Browser nachher aufrufbar: activate :livereload, :host => '0.0.0.0', :no_swf => true Was in meinem Fall noch wichtig war: Das Assset hashing darf nicht ausserhalb der build Konfiguration aktiviert sein, andernfalls wird kein JavaScript beim Middleman-server injected.

Was nun noch wichtig ist: Das von VirtualBox verwendete Filesystem-Mounting unterstuetzt kein notify. Damit muss der middleman server zwingend den Polling-Modus verwenden: middleman server --force-polling Der einzige Wermutstropfen: Das funktioniert natürlich dann nur auf dem Entwicklungsrechner. Mit ipad oder Android Telefon im WLAN kommt man mit dem "0.0.0.0" nicht weit. Aber immerhin funktioniert so das live reload mit vagrant.

Vagrant + Nginx/Apache: Korrupte Daten bei statischen Dateien

7 December 2013

Das hat echt eine Weile gedauert dieses Yak zu shaven: Dank Vagrant und VirtualBox habe ich ein Web-Projekt mit einer leicht zu startenden Entwicklungsumgebung versehen.

Das hat vorher auch schon prima geklappt, und das Verfahren hat sich bewährt - besonders, wenn das Setup etwas komplexer ist, oder es Entwickler gibt die nicht mit Linux/Debian/Ubuntu arbeiten. Jedoch hat mich heute ein Bug gequält den ich wirklich einige Stunden suchen durfte. Alles fing damit an, dass es JavaScript Fehler hagelte. Uncaught SyntaxError: Unexpected token ILLEGAL Jedoch nur, wenn die Datei aus Vagrant per nginx ausgeliefert wurde. Mit Netbeans und dem eingebauten mini-Webserver für HTML5 Projekte lief alles super.

Eine Google Suche brachte unglaublich viele Ergebnisse - jedoch keine Lösung. Man solle nach bösen Zeichen schauen, am besten nach Whitespace das komisch ist. Eine super Chance auf den Holzweg abzubiegen und da eine Weile unterwegs zu sein.

Die Quellcode-Ansicht von Firefox brachte dann erstaunliches zu Tage:

Screenshot from 2013-12-07 21:30:49

Das sieht in der Tat kaputt aus. Mal schnell im Editor schauen - nein da ist alles gut. Auf der Vagrant Maschine nachschauen, auch da alles in Ordnung. (Sowas in der Art hatte ich schonmal wenn die Guest-Additions von VirtualBox nicht mehr so recht zur Umgebung passen. Aber das war hier nicht der Fall.)

Auch das Einfügen von dummy-Text änderte weder etwas an dem Muell am Ende der Datei, noch wurde der Text angezeigt. Nanu, was kann das sein? Schnell noch einen Holzweg her! "Ist bestimmt Caching."

Das Rätsels Lösung ist dann ein 5 Jahre alter Bug in VirtualBox, wohl auch bei Apache oder sogar Versionsverwaltungssoftware zuschlagen kann: VirtualBox hat Probleme mit direktem mmap zwischen zwei Filehandles, wenn es sich dabei um per vboxfs gemountete Verzeichnisse handelt.

Hier das Ticket dazu: https://www.virtualbox.org/ticket/819

Bei nginx kann man sendfile sehr einfach ausschalten: sendfile off; Danach klappt alles wie erwartet.

Java Memory-Leaks mit plumbr finden

2 April 2013

Java hat einen schlechten Ruf, auch heute noch: Langsam, braucht zu viel Speicher, umständlich und und und. Das mit dem Speicher ist bei Java gerade bei Webanwendungen (oder Enterprise-Anwendungen) wirklich so eine Sache. Bei nicht wenigen Projekten habe ich gesehen, dass Java Server (Tomcat, Websphere, ...) Nachts regelmäßig durchgestartet werden, um dafür zu sorgen, dass es keine Speicherprobleme gibt.
Die Speicherprobleme kommen jedoch nicht von Java selbst, sondern es handelt sich in der Regel um Memory-Leaks. Diese können auch bei manueller Speicherverwaltung (malloc/free vs. Garbage Collection bei Java) auftreten. Eine ganz besondere Form von Speicherlecks sind sogenannte "Permgen-Leaks". Permgen ist der Speicherbereich der Sun/Oracle Hotspot VM in der z.B. Java Klassen gehalten werden. Solange diese gebraucht werden, bleiben die Klassen geladen. Klassen gehören zu einem Classloader, eine Klasse, die von verschiedenen Classloadern geladen wurde, stellt sich der Anwendung in der Regel als verschiedene Klassen dar. Die damit einhergehenden Probleme wenn das innerhalb der selben Anwendung passiert können nochmal ganz andere sein.
Bei Web-Anwendungen gibt es einen Classloader, der für eine deployte (oder deutsch "verteilte", "zur Verfügung gestellte") zuständig ist. Wird die Anwendung undeployt, jedoch der Container (Tomcat z.B.) nicht heruntergefahren sollte dennoch der Speicher der Anwendung, insbesondere auch der Permgen Speicher, wieder freigegeben werden.
Passiert das nicht, führt das unweigerlich nach mehreren Re-Deployments zu einem "Out of Memory: Permgen" Problem.
Aus diesem Grund werden dann oft die Server zusammen mit dem Deployment neu gestartet. Das kann Zeit kosten und ist in meinen Augen die Garantie dafür, dass die Speicherlecks auch dauerhaft nicht behoben werden: Die Entwickler spüren die Schmerzen nicht, das senkt die Motivation etwas zu tun. Bewegt man sich in Richtung Continuous-Integration oder gar Continuous-Deployment kommt ständiges Neustarten von Servern nicht in Frage: Es dauert lange, Caches sind danach kalt.
Bisher habe ich Speicherlecks daher stets gejagt: VisualVM (Sun/Oracle, Teil des JDK), Eclipse MAT (SAP Entwicklung, OpenSource) oder auch YourKit (Profiler, kommerziell) und findbugs (OpenSource) haben mir gute Dienste geleistet. Kommt man ohne EAR aus, hilft auch der in Tomcat integrierte Memory-Leaks-Prevention-Listener, ähnliches bietet auch Jetty. Nicht immer hat man reines WAR deployment oder nur Java Servlets, und die manuelle Suche kann sehr zeitintensiv werden.

Netbeans + git = merge commit bei pull?

16 March 2013

Netbeans unterstützt derzeit keine interaktive Auswahl der Optionen "merge commit" oder "rebase" wenn bei einem git pull kein fast-forward möglich ist. Dazu gibt es diesen Netbeans bug: http://netbeans.org/bugzilla/show_bug.cgi?id=213855

Als kleiner Work-Around ist es jedoch mit git Bordmitteln möglich, das Default-Verhalten von git selbst anzupassen. Dazu kann man auf einem Branch das Verhalten konfigurieren, z.B. dem master branch: git config branch.master.rebase true

Ich hoffe dieser kleine Netbeans Tipp hilft auch anderen Usern :)

jQuery anchor hash Selektor

21 April 2012

In älteren Versionen von jQuery konnte man einen Selektor für den hash Wert von Links schreiben. (Der Hash Wert ist der Teil hinter "#" in einem Link element, man kann damit verschiedene Bereiche in einer Seite anspringen.)

Das sah mit jQuery 1.2.6 z.B. so aus: $("a[hash='#sprungMarke']"); Bei neueren jQuery Versionen ist das nicht mehr so explizit möglich. Dafuer gibt es jedoch Selektoren mit denen man auf Inhalte und partielle Inhalte von Attributen matchen kann. Hiermit ist es dann wieder möglich auf den Hash Wert zu matchen, denn es handelt sich dabei gerade um das Ende des "href" Attributes eines Links.

Mittels "$" kann man das Suffix-Matching für den Wert eines Attributes machen.

Damit sieht das dann so aus: $("a[href$='#sprungMarke']");

Die neuen, flexibleren, Selektoren von jQuery können also Arbeit sparen, wenn man sich ihrer Mächtigkeit bewusst ist.

Glassfish 3.1: Probleme mit DWR 2 (und mehr)

28 February 2011

Oracle hat heute den Glassfish 3.1 freigegeben - gleichzeitig als Open Source und als Oracle Glassfish Edition. Es gibt eine Menge neues, und dazu gehören auch neue Probleme.

Ich verwende Glassfish schon seit geraumer Zeit um mittels "Continuous Deployment" für aktuell entwickelte Anwendungen eine separate Umgebung zu haben, in der ich und Kollegen testen können. Das ganze funktioniert mittels eine CI-Servers (Hudson Jenkins in diesem Fall), Maven und einem Deploy Plugin.

Auch mit Glassfish 3.1 funktionierte das Deployment prima - also hier war kein Update von Jenkins oder dem Deploy Plugin erforderlich. Auch die Anwendung startete - jedoch funktionierte nichts. Exceptions über ungültige Sessions gab es, auch Log-Einträge vom hier für Ajax eingesetzten DWR (Direct Web Remoting) 2011-02-28 18:57:13,037 [http-thread-pool-8090(2)] ERROR o.d.dwrp.Batch - A request has been denied as a potential CSRF attack.
2011-02-28 19:03:02,105 [http-thread-pool-8090(5)] ERROR o.d.dwrp.Batch - A request has been denied as a potential CSRF attack.
Dank Firebug etwas schlauem Rumraten und Probieren fand ich dann heraus: Glassfish 3.1 setzt Session Cookies per Default auf "HTTP Only". Dazu gibt es bereits ein Ticket im Glassfish Tracker: GLASSFISH-15730

Es gibt nun mehrere Möglichkeiten für die nötige Kompatibilität mit Bestandsanwendungen zu sorgen:

Wird man die Anwendung zukünftig immer in einem Servlet 3.0 kompatiblen Container deployen, so kann man in der web.xml das Verhalten umkonfigurieren:

<web-app>
  <session-config>
    <cookie-config>
      <http-only>true</http-only>
    </cookie-config>
  </session-config>
</web-app>
Alternativ kann man bei DWR den CSRF Check deaktivieren, wovon ich jedoch abraten würde:
<servlet>
  <servlet-name>dwr-invoker</servlet-name>
  <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
  <init-param>
    <param-name>crossDomainSessionSecurity</param-name>
    <param-value>false</param-value>
  </init-param>
</servlet>
Die letzte Möglichkeit ist - in diesem Fall - auf DWR 3 umzustellen, hier wurde das Problem grundsätzlich gelöst, so dass nicht mehr per JavaScript auf den Session Cookie zugegriffen werden muss. (Siehe DWR-26) Leider gibt es von DWR 3 bisher noch kein Release, sondern lediglich vorab-Versionen.

Das Problem tritt übrigens auch mit Tomcat 7 auf, und nicht nur mit Glassfish 3.1 - ich frage mich, ob dies Verhalten am Ende sogar in der Servlet 3 Spezifikation vorgegeben ist.
Natürlich betrifft dies nicht ausschließlich DWR, sondern auch andere Anwendungen, die per JavaScript auf den Session Cookie zugreifen wollen/müssen.

Maven, Jetty und Reloads: Session persistieren

22 January 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.

Java Servlet (Spring Controller) auf Root Path mappen

12 January 2011

Nicht immer genuegt es, wenn man ein Servlets auf andere Pfade oder Patterns mappt, manchmal möchte man bereits auf den Context Root ein Servlet mappen. Der übliche Work-Around sieht so aus, dass man bspw. in einer "index.jsp" einen redirect auf eine tatsächlich einem Servlet zugeordnete URL (über den Pfad oder Datei Extension) macht, das könnte so aussehen: <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:redirect url="/myServlet"/>
Das ist aber nicht immer praktikabel - nun soll es darum gehen ein Servlet direkt auf den "/" Pfad zu mappen - dafür gibt es mehrere Möglichkeiten:

  1. Das Default Servlet ersetzen, dazu wird auf den Root Pfad "/" in der web.xml ein Mapping angelegt: <servlet-mapping> <servlet-name>myServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
  2. Ab Servlet Spezifikation kann auch ein Servlet in der welcome-file-list in der web.xml gemappt werden: <welcome-file-list> <welcome-file>myServlet</welcome-file> <welcome-file>index.html</welcome-file> <welcome-file>index.jsp</welcome-file> </welcome-file-list>

Im folgenden beschreibe ich die Vor- und Nachteile der verschiedenen Ansätze, und welche Erfahrungen ich mit verschiedenen Web Containern dabei gemacht habe.

Netbeans: "package javax.servlet.jsp does not exist" (cannot find symbol)

7 January 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.

web.xml Tag Reihenfolge: Relevant!

18 December 2010

Eine weitere Erfahrung mit Glassfish gemacht - und was dazu gelernt. Zumindest bei der Servlet 2.4 Spezifikation ist die Reihenfolge der inneren Tags im web.xml Deployment Descriptor relevant. Während Tomcat zufrieden dahin schnurrt, wenn man dies nicht beachtet, gibt es Fehler beim Deployment im Glassfish: com.sun.enterprise.admin.cli.CommandException: remote failure: Exception while deploying the app : java.io.IOException: org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'servlet-name'. One of '{"http://java.sun.com/xml/ns/j2ee":filter-name}' is expected. oder com.sun.enterprise.admin.cli.CommandException: remote failure: Exception while deploying the app : java.io.IOException: org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'url-pattern'. One of '{"http://java.sun.com/xml/ns/j2ee":servlet-name}' is expected. Dabei ist das kein Fehler vom Glassfish: Er hält sich streng an die Spezifikation und validiert die web.xml beim Parsen mit SAX (Streaming Parser) gegen die DTD.

Also einfach darauf achten: Erst kommt der Servlet/Filter Name und dann die Zuordnung auf ein URL-Pattern bzw. bei Filtern auch auf einen Servlet Namen, wie im folgenden Beispiel: <servlet-mapping>
<servlet-name>admin</servlet-name>
<url-pattern>/admin/*</url-pattern>
</servlet-mapping>

<filter-mapping>
<filter-name>cacheFilter</filter-name>
<servlet-name>print</servlet-name>
</filter-mapping>
Ab Servlet Spec 2.5 darf man übrigens auch mehrere Mappings auf einmal angeben - falls man noch mit der web.xml und nicht mit Annotationen arbeitet spart es Tipparbeit und ist übersichtlicher.

Maven Properties werden falsch gefiltert?

15 December 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

Firefox langsam und braucht viel Speicher?

6 December 2010

Firefox ist an sich ein recht ordentlicher Browser. Die Zeiten in denen er in Punkto Geschwindigkeit und "Schlankheit" ganz vorne war, sind allerdings vorbei. Aber damit koennen viele gut Leben - Firefox ist recht stabil, die Geschwindigkeit ist auch nicht schlecht und vor allem die Flexibilitaet dank der beinahe unendlichen Fuelle an Erweiterungen (Extensions / Add-Ons) machen den Firefox Browser attraktiv.

Dabei spielt es keine Rolle, ob es um Entwickler geht, die Firebug mit den dafür ebenfalls verfügbaren diversen Erweiterungen nutzen, oder den Gelegenheitssurfer der dank Adblock-Plus schneller und weniger genervt das Internet konsumieren kann. Für andere Nischen und spezielle Bedürfnisse gibt es ebenso viele Plugins von "Spass" bis "Produktivität" ist alles vertreten.

Jedoch wuchs der Neid bei mir wenn ich auf Chrome / Chromium blickte - ich wollte Firefox auch etwas schneller haben. Bekannt für Nachteile bei der Performance sind eben gerade jene Erweiterungen, die einem das Leben so schön erleichtern. Also habe ich einige deaktiviert, es wurde in der tat etwas schneller. Damit war das erledigt. Erfolg!

Bis mir auffiel, dass irgendetwas nicht stimmte. Bei Downloads verschlang Firefox immense Mengen an Speicher - ein Vielfaches dessen, was die Datei selber haben würde. Und auch die CPU Belastung, vor allem bei Downloads, wuchs dramatisch.

Erst hatte ich das Flashplugin in Verdacht - in der Regel trifft man damit den Richtigen, genauso wie pauschal auf Windows schimpfen. Aber daran lag es nicht, ich hatte extra keine Flash Seiten aufgemacht.

Erst als ich alle von Firebug abhaengigen Erweiterungen (und nicht nur Firebug selber) deaktiviert hatte, sowie TamperData und LiveHttpHeaders war endlich alles wie es sein sollte. Firefox brauchte weder Unmengen an Memory noch ging die CPU Last bei Downloads in die Höhe. Welches Plugin tatsächlich verantwortlich war, habe ich nicht mehr untersucht. Vermutlich ist es nicht gut, wenn man Plugins, die Firebug benötigen, aktiviert lässt, aber Firebug selber deaktiviert.

Um mir Arbeit zu sparen (wer moechte schon immer alle Erweiterungen ein- und ausschalten) habe ich mir mittels eine zweiten Firefox Profils das Leben leichter gemacht: Es gibt jetzt ein "dev" Profil für Entwicklung, da ist dann alles aktiviert, dass sich der Web-Entwickler wünscht. Daneben sind auch deutlich weniger, bzw. andere Bookmarks gesetzt: "Führe mich nicht in Versuchung".

Um den Entwicklungs-Firefox zu starten, habe ich mir eine zusaetzliche Verknuepfung (mit Werkzeug-Symbol) in der Ubuntu Linux Taskbar angelegt, diese ruft folgendes Kommando auf: firefox -no-remote -P dev Mittels "-P" kann man das Profil auswählen, welches verwendet werden soll, das "-no-remote" verhindert, dass bei einer bereits gestarteten Firefox Instanz (z.B. des default Profils) lediglich ein neues Fenster aufgemacht wird.

Probiert es mal aus - Kommentare und Feedback erwünscht!

Yahoo 1337 - Leet Backlinks

6 December 2010

Manchmal kann man bestimmte Assoziationen einfach nicht verhindern. Als Computer-Kind bedeutet die 1337 etwas besonderes (siehe auch Leetspeak) und so schmunzelte ich doch sehr als die Webanalyse Software Piwik mir folgende Backlink Statistik präsentierte:

Piwik ist übrigens eine interessante Alternative zu Google Analytics, es handelt sich um eine kostenlose OpenSource Software, die mittels JavaScript, PHP und MySQL Webseitenstatistiken erzeugt. Bei großen Projekten wird die Last auf der Datenbank allerdings deutlich spürbar - vielleicht ist eine relationale Datenbank für Webanalyse eben nicht so gut, wie BigTable (Google) oder andere NoSQL Systeme. Im Gegensatz zu Google Analytics liefert Piwik jedoch auch eine Backlink, Pagerank und Alexa Analyse direkt dazu.

Mysql und phpmyadmin: Daten encoded und falsch angezeigt?

10 August 2010

Bei der Migration einer MySQL Datenbank gab es ein merkwürdiges Phänomen: Nach dem Import der Daten von einem Server auf einen Ubuntu Lucid Server wurden die Daten falsch angezeigt. Es sah aus, als wenn sie base64 codiert wären, oder ein esoterisches Encoding Problem zugeschlagen hätte.

Die Vermutung lag nahe, dass entweder der Dump (mittels mysqldump erzeugt) defekt war, oder falsch importiert wurde. (Der Import wurde über den mysql Kommandozeilen Client gemacht, MySQL lag auf beiden Systemen in der Ubuntu Lucid Version 5.1.41 vor.). Das Thema MySQL, Encoding, Collation und Charset kann sich dabei als sehr verwirrend herausstellen.

SpringSource/Vmware: FAIL dank Google Analytics

13 January 2010

Das habe ich bisher noch nie gesehen. Die gesamte Webseite an Google geopfert! Aber von vorne: SpringSource, der Hersteller des Spring Framework, bietet auf seiner Webseite Downloads und andere interaktive Elemente an.
Auf der Webseite kommt Google Analytics zum Einsatz, und natürlich auch JavaScript. Das frappierende: Ist JavaScript deaktiviert, oder Google Analytics geblockt, funktioniert die Webseite nicht mehr richtig. In der Tat hat damit SpringSource, die Firma die stets "loose coupling" und "keine Abhängigkeiten" als Verkaufsargumente nutzte eine Abhängigkeit zu Google eingeführt.

jQuery: HTML Inhalt einfärben

30 December 2009

Es kam die Frage auf, wie man bei einer Web Anwendung, bei der die Ausgabe vorgegeben ist, die Präsentation anpassen kann. Ohne eben die Web Anwendung ändern zu müssen.
Wenn man auf die Ausgabe gewissen Einfluss hat (z.B. über Templates), so kann man mit JavaScript und jQuery sehr einfach Anpassungen vornehmen - sogar aufgrund des HTML Inhalts. (In diesem Fall ging es um die optische Anpassung von Tabellen Zeilen, wenn es sich um premium Kunden handelt.)

Chromium Browser: Schneller Entwickeln!

1 August 2009

Welche IDE man bevorzugt, darüber kann man sicherlich vortrefflich streiten. Genauso übrigens auch über Webbrowser. Doch eins ist klar: Bei der Entwicklung zählt jede gesparte Sekunde. Gerade in Webanwendungen wird man nicht um manuelles Testen und Ausprobieren herumkommen. Ich habe gemerkt, dass man mit dem Firefox (Firebug, Webdeveloper Toolbar, etc. pp) wunderbar Debugging betreiben kann. Das Tooling ist in meinen Augen ungeschlagen.

Canoo Webtest: NullPointerException durch JavaScript

15 May 2009

Canoo Webtest bietet seit einiger Zeit auch (begrenzte) Unterstützung für JavaScript. Das ist gerade zum Testen von Web 2.0 Anwendungen interessant, kann jedoch auch zu sehr merkwürdigen Fehlern führen.

In meinem Fall quittierte Webtest die Arbeit mit der hilfreichen Meldung com.gargoylesoftware.htmlunit.ScriptException: Wrapped java.lang.NullPointerException

Canoo Webtest: GUI monitor deaktivieren

14 May 2009

Canoo Webtest ist ein auf ant und Groovy basierendes Framework zum automatisierten Testen von Webanwendungen. Anders als beispielsweise bei Selenium wird HTMLUnit als "Browser" verwendet.

Die Dokumentation von Webtest läßt jedoch trotz der zeitlichen Reife des Projektes an einigen Stellen zu wünschen übrig. Hier kann ein Blick in "webtest.xml" sowie in "resources/build/WebTestReport.reference.xml" im Installationsverzeichnis von Webtest etwas inspirieren.

Java/JavaFX -> iPhone + IpodTouch?

5 March 2009

Sun hat mit JavaFX ein großes Vorhaben gestartet: JavaFX soll Java in einem Bereich populär machen, in dem Java ursprünglich brillierte: Rich Internet applications (RIA). Damals waren es die Java Applets, die für Lauftext, interaktive Menüs und ganze Lernprogramme eingesetzt wurde.

JavaFX soll eine neue Generation von Internet Anwendungen einläuten, Desigern wie Entwicklern neue Möglichkeiten an die Hand geben. Und mit JavaFX mobile soll die Philosophie "write once, run everywhere" für mobile Anwendungen wahr(er) werden. JavaFX Mobile wird auf Blackberrys, Android und anderen Mobilgeräten laufen, solange zumindest JavaME vorhanden ist. (Die JavaFX Mobile runtime wird ggf. nachinstalliert) Auch wenn Nokia noch nicht offiziell im Boot ist, könnte ich mir eine entsprechende Ankündigung zur JavaOne gut vorstellen.

Doch was ist mit Java und dem iPhone von Apple? Auch der Apple ipod touch, der eine ähnliche Plattform wie das iPhone darstellt besitzt derzeit weder Flash noch Java Support. (Wenn man von einem Jailbreak Gerät absieht.)

Google Admanager Debugging

11 December 2008

Gerade wenn es um die Integration von gehosteten Applikationen von Drittanbietern geht, wird Debugging oft eine Tortur. Google bietet mit dem Admanager genau so eine Applikation als Dienstleistung: Einen Adserver.

Google wäre aber nicht Google, wenn es hier nich auch ein paar schlaue Kniffe gäbe - der Admanager bekommt stets die URL der Seite, auf der Werbung eingebunden wird übermittelt. Damit lassen sich dann auch Parameter übergeben. Der Google Admanager Code lauscht hier auf "google_debug" als Parameter und öffnet dann Debug Informationen in einem Popup.

Hier sind dann einige hilfreiche Dinge zu sehen:

  • Für welche AdSlots wurden Daten angefragt?
  • Für welche AdSlots liegen Werbemittel vor - und welche?
  • Wie lange wurde der Seitenaufbau durch das Nachladen von Werbemitteln aufgehalten?
  • Wie lange wurde der Seitenaufbau durch die Darstellung der Werbemittel verzögert?

admanager-debugging

Sehr schön ist anhand der Timeline auch nachzuvollziehen zu welchem Zeitpunkt welche Ereignisse stattgefunden haben. Ein Paradebeispiel für erleichtertes Debugging bei JavaScript/Ajax Anwendungen.

JavaScript Error mit Google Admanager und adblock vermeiden

11 December 2008

Der Google Admanager ( http://www.google.com/admanager/ ) ist ein kostenloses Google Produkt, um Werbebuchungen zu verwalten.

Der Google Admanger arbeitet dabei mit JavaScript um Werbemittel in die Webseite zu integrieren - z.B. auch Google Adsene. Viele Surfer benutzen inzwischen einen Werbeblocker, wie z.B. den Firefox Adblock plus - hier kommt es nun zu JavaScript Fehlermeldungen, die man vielleicht als Webmaster vermeiden möchte.

Internet Explorer (IE) 6 und das Bilder Caching

9 December 2008

Der IE 6 ist sicherlich schon betagt, was aber noch lange nicht bedeutet, dass er nicht noch reichlich Verwendung finden würde. Besonders wenn für eine Kundensoftware Internet Explorer 6 zwingend unterstützt werden muss, kann man sich auf viele Überraschungen gefaßt machen.

Eine davon ist der Umgang mit CSS (background) Bildern und dem Cache des Internet Explorer. Normalerweise sollte ein Webbrowser Elemente (wie z.B. Grafiken) nur einmal laden, und dann im internen Cache bereithalten, um ggf. wiederverwendet zu werden. Da häufig Elemente auf Webseiten - besonders Hintergrundgrafiken und Style Elemente - wiederkehrend sind, kann man damit Bandbreite und natürlich auch Zeit sparen.

Browser Speed - was ist drann an Chrome, V8 und Co?

6 December 2008

Nichts hilft weniger als synthetische Benchmarks, wenn es darum geht, Produkte zu vergleichen. Das fängt bei Akkulaufzeit von Handys an, und hört noch lange nicht beim Spritverbrauch von Autos auf.

In der letzten Zeit sind Browser-Benchmarks total angesagt, vor allem JavaScript Benchmarks die mehr oder minder zeigen sollen, wer den längeren schnelleren Browser hat. Doch wie aussagekräftig ist das nun wirklich? Bei der Entwicklung einer browser basierten Anwendung, die stark auf Ajax (JQuery, DWR) zurückgreift, während auf dem Server eine JEE Anwendung mit Drools werkelt.

Hier hatte ich nun die Chance, ein paar "echte" Daten zu sammeln - und mir Gedanken zu machen.

Fileupload für Bilder mit jQuery - dank Ajax mit Vorschaufunktion

28 November 2008

Gerade wenn es um sogenannten user generated content geht, ist es immer schön, wenn man eine Vorschaufunktion anbieten kann. Ein Knopf "Vorschau" ist ziemlich 1990 - es lebe das Web 2.0 mit Ajax, jQuery und vielen Hacks.

Ich hatte bereits darüber gebloggt wie man mittels jQuery und etwas Tricksen einen "Ajax Fileupload" realisert. Noch schöner ist es natürlich, wenn der User sofort Feedback bekommt, wie sein ausgewähltes Bild wohl aussehen würde. Dazu lädt man das Bild schon direkt nachdem der User eine Datei ausgewählt hat, und zeigt diese an. An Browser-Caches muss man vielleicht noch denken, aber auch hier kann JavaScript bzw. jQuery helfen.

Das Vorgehen:

  1. Man hängt einen Listener an die Change Methode des Input Felds
  2. Wie in meinem letzten Beitrag beschrieben wird der Upload über ein Iframe realisiert
  3. Nun biegt man noch die Bild URL um und zeigt somit das Resultat an

Hier der Quellcode: (das Formular heißt "logoUploadForm", das input Feld für das Image File "logo".
Ajax Fileupload handling - und Bild URL umbiegen nach dem Upload. //handle file upload with hidden iframe
jQuery("#logoUploadForm").submit( function(data)
{
var submittingForm = jQuery( this );
var frameName = ("upload"+(new Date()).getTime());
var uploadFrame = jQuery("<iframe name=\""+frameName+"\" />");
uploadFrame.css("display", "none");
uploadFrame.load(function(data){
//submit is complete here
setTimeout(function(){
//update image
var imageDiv = jQuery("#print_logoImage");
var logoUrl = imageDiv.attr("src").split("?")[0];
imageDiv.attr("src", logoUrl+"?"+ (new Date()).getTime());
//remove hidden upload frame
uploadFrame.remove();},1000);
});
jQuery("body:first").append(uploadFrame);
//setup complete
submittingForm.attr("target", frameName);
});
Hier noch der Code zum "sofort upload": jQuery("input[name=logo]").change(function (){
jQuery("#logoUploadForm").submit();
});
Das wars - ausprobieren!

Ajax File upload mit jQuery - ohne DWR

16 November 2008

Ajax ist eine tolle Erfindung - bis auf ein paar "Kleinigkeiten". Z.B. ist nicht vorgesehen einen Dateiupload mittels Ajax zu realisieren. Da muss schon ein echtes Formular her.

Doch wenn dennoch eine Datei im Hintergrund hochgeladen werden soll - also ein "echter" Ajax File upload realisiert werden soll - greift man in die kreative Trickkiste. Die üblichen Verdächtigen für solche Aufgaben sind DWR, jQuery, Dojo. DWR bringt in der Inkarnation 3.0 dann auch Support für Ajax Fileupload, inclusive einem Mapper. Also zurück zu den Basics - was tun, wenn ein XmlHttpRequest nicht da ist? Richtig! Unsichtbares iframe nehmen.

GWT (Google Web Toolkit) zum Mitreden

14 June 2008

GWT zum Mitreden: Informationen zum Google Web Toolkit, die für einen Vortrag zusammengestellt wurden.

GWT: Google Web Toolkit wird erwachsen

21 April 2008

Das Google Web Toolkit wird erwachsen - das behauptet Google zwar nicht selber, doch das Umfeld spricht eine deutliche Sprache. GWT 1.5 wird endlich - lang ersehnt - Java 5 und damit auch die Generics von Java 5 unterstützen. Auch wenn noch keine fertige 1.5 Version von GWT vorliegt, so arbeiten bei Google eifrig die Entwickler an dem OpenSource Projekt. Google Web Toolkit

Während von GWT 1.5 inzwischen Milestone 2 verfügbar ist, wächst auch das Ökosystem rund um das Google Web Toolkit:

GQuery ist eine typsichere Umsetzung von jQuery für GWT - wer jQuery kennengelernt hat, wird es sicherlich auf Anhieb lieben.

GWT-SL, die Google Webtoolkit Server Library zielt auf Spring Framework Integration ab: Spring Beans können als RPC Dienste exportiert werden, und macht so die Integration in bestehende Entwicklungs-Stacks oder auch Applikationen einfacher.

Hibernate4GWT schließlich rundet das ganze ab: Hibernate persistierte Objekte (und lazy collections) können ohne Verrenkungen mit GWT verwendet werden. Mit GWT 1.5 und Java Generics wird das sicherlich noch ein großes Stück angenehmer.


/
Copyright © 2007, 2008 everflux. Alle Rechte vorbehalten. All rights reserved.