<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>PINC-Blog</title>
	<atom:link href="http://www.pincservices.de/wordpress/feed" rel="self" type="application/rss+xml" />
	<link>http://www.pincservices.de/wordpress</link>
	<description>yet another developer blog</description>
	<lastBuildDate>Sat, 10 Sep 2011 07:53:09 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>Quelle aller Worte: Internationalisierung mit GWT UIBinder</title>
		<link>http://www.pincservices.de/wordpress/quelle-aller-worte-internationlisierung-mit-gwt-uibinder</link>
		<comments>http://www.pincservices.de/wordpress/quelle-aller-worte-internationlisierung-mit-gwt-uibinder#comments</comments>
		<pubDate>Sat, 10 Sep 2011 07:49:49 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Softwaredesign]]></category>
		<category><![CDATA[Webentwicklung]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[i18n]]></category>
		<category><![CDATA[internationalization]]></category>
		<category><![CDATA[LocalizableResource]]></category>
		<category><![CDATA[UIBinder]]></category>

		<guid isPermaLink="false">http://www.pincservices.de/wordpress/?p=581</guid>
		<description><![CDATA[Als Gott sah was beim Turmbau zu Babel passierte, entschied er sich die Sprache der Menschen zu teilen, so dass der Eine den Anderen nicht mehr verstehen möge. Ähnlich scheinen sich die Designer von GWT gefühlt haben, als sie die Internationalisierung von GWT 2.x entworfen haben. Das Internationalisierungsprinzip von GWT ist an sich sehr einfach. [...]]]></description>
			<content:encoded><![CDATA[<p>Als Gott sah was beim Turmbau zu Babel passierte, entschied er sich die Sprache der Menschen zu teilen, so dass der Eine den Anderen nicht mehr verstehen möge. Ähnlich scheinen sich die Designer von GWT gefühlt haben, als sie die Internationalisierung von GWT 2.x entworfen haben.</p>
<p>Das Internationalisierungsprinzip von GWT ist an sich sehr einfach. Man nehme ein paar <code>properties</code>-Dateien, inkludiere das I18N-Modul und lasse sich die entsprechende Java-Datei generieren. Soweit so gut. Leider nicht so, wenn man den UIBinder verwenden möchte. Hier haben sich bereits diverse verzweifelte Entwickler einen &#8220;abgebrochen&#8221; um herauszufinden, welche Dateien an welcher Stelle liegen müssen, damit man in den jeweiligen <code>ui.xml</code>-Dateien eine vernünftige Übersetzung erhält. </p>
<p>Grundsätzlich gilt, dass Übersetzungs-Keys aus <code>ui.xml</code>-Dateien immer im Package <code>com.google.gwt.i18n.client</code> mit dem Namen <code>LocalizableResource_[locale].properties</code> liegen müssen. Diesen Umstand verdanken wir dem <code>MessagesWriter</code>, der vom <code>UiBinderGenerator</code> herangezogen wird. Dieser generiert zwar die Messages-Dateien für alle Keys, die sich in einer <code>ui.xml</code>-Datei befinden in eine eigene <code>Messages</code>-Klasse, importiert aber mittels</p>
<pre class="brush: plain;">
writer.write(&quot;import static com.google.gwt.i18n.client.LocalizableResource.*;&quot;);
</pre>
<p>ausschließlich die Übersetzungen aus <code>LocalizableResource</code>. Soweit so gut, möchte man meinen. Problematisch wird es dann, wenn man Übersetzungen sowohl im Java-Code, als auch im in den ui-Dateien haben will. Typisches Beispiel sind hier Tabellen vom Typ <code>CellTable</code>, deren Spalten normalerweise in den View-Klassen definiert werden. Will man hier nun sprachlich angepasste Spaltenköpfe haben, muss man diese mittels einer <code>Messages</code>-Klasse übersetzen.<br />
In diesem Moment steht man vor der Frage: Möchte ich zwei Übersetzungsdateien verwalten, in denen ggf. Keys doppelt auftreten, oder möchte ich nur Eine für beide Mechanismen haben?</p>
<p>Ohne auf die unsäglichen und teilweise unpraktikablen Varianten einzugehen, die sich im Netz bereits befinden bzw. die kryptisch auf der GWT-Dokumentation vorgestellt wurde, stelle ich hier meine zwei Lösungen vor, die ich für sinnvoll erachte.</p>
<h3>Variante 1: <code>ui:with</code></h3>
<p>Die klassische Variante. Man nehme einfach die existierenden Messages und importiere sie wie folgt in die <code>ui.xml</code>-Datei.</p>
<pre class="brush: plain;">
 &lt;ui:with field='messages' type='com.my.app.MyMessages'/&gt;
 &lt;g:Label text=&quot;{messages.hello}&quot; /&gt;
</pre>
<p>Diese Variante hat den Vorteil, dass man auf die komplette Bandbreite der Erweiterungen, die für <code>Messages</code>-Klassen bereitgestellt wurde zugreifen kann. </p>
<h3>Variante 2: Customized <code>Messages</code>-Interface</h3>
<p>In Variante 1 nutzen wir den Mechanismus, der eigentlich für den Java-Code gedacht war für den UiBinder. Natürlich geht es auch anders herum. Wir &#8220;kopieren&#8221; einfach den Mechanismus der <code>MessagesWriter</code>-Klasse. Wir bauen uns ein Interface und importieren die LocalizableResources.</p>
<pre class="brush: plain;">
package com.mypackage;

import static com.google.gwt.i18n.client.LocalizableResource.*;

public interface MyAppMessages extends Messages {
  @DefaultMessage(&quot;Example&quot;)
  String example();
}
</pre>
<p>Der GWT-Compiler greift hier einfach das Interface und verknüpft die Methoden mit den Keys aus der jeweiligen LocalizableResource-Datei. Damit lassen sich auch innerhalb von Java-Dateien die Keys aus LocalizableResource verwenden.</p>
<p><b>Achtung:</b><br />
<i>Leider gibt es nicht die Möglichkeit LocalizableResource-Dateien über den i18n-Aufruf in eine Klasse übersetzen zu lassen, da <code>LocalizableResource</code> bereits ein existierendes Interface ist und die Übersetzung zu einer sogenannten zyklischen Vererbung führt.</i></p>
<h3>Fazit</h3>
<p>Mit beiden Varianten lässt sich das bestehende Problem lösen, dass man nur einen Mechanismus zur Internationalisierung innerhalb von GWT-Projekten nutzen möchte. Welche der beiden zum Einsatz kommt hängt stark von der bestehenden Struktur und &#8211; was nicht zur vernachlässigen ist &#8211; von der Motivation des Entwicklers, welche Schritte für ihn in seinem Arbeitsprozess besser integriert werden können, ab. Während Variante 1 den Aufruf des i18n-Creators erfordert, muss in Variante 2 das Interface immer manuell angepasst werden.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pincservices.de/wordpress/quelle-aller-worte-internationlisierung-mit-gwt-uibinder/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Trügerische Sicherheit: Fehlermeldungen ohne Kontextinformationen</title>
		<link>http://www.pincservices.de/wordpress/trugerische-sicherheit-fehlermeldungen-ohne-kontextinformationen</link>
		<comments>http://www.pincservices.de/wordpress/trugerische-sicherheit-fehlermeldungen-ohne-kontextinformationen#comments</comments>
		<pubDate>Thu, 30 Jun 2011 18:43:58 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Softwaredesign]]></category>
		<category><![CDATA[context information]]></category>
		<category><![CDATA[error messages]]></category>
		<category><![CDATA[software design]]></category>

		<guid isPermaLink="false">http://www.pincservices.de/wordpress/?p=570</guid>
		<description><![CDATA[Die Applikation. Unendliche Weiten. &#8230; *räusper* So schlimm ist die Welt der Software-Entwicklung nun zwar auch nicht, dass man blindlinks irgendwo im Dunkeln rumdüst und völlig überraschend in einer Raumzeit-Anomalie hängt oder von Q für die Verbrechen der Menschheit angeklagt wird. Aber gerade bei neuen Software-System hat man viele Stellen noch nicht berührt und muss [...]]]></description>
			<content:encoded><![CDATA[<p>Die Applikation. Unendliche Weiten. &#8230; *räusper*</p>
<p>So schlimm ist die Welt der Software-Entwicklung nun zwar auch nicht, dass man blindlinks irgendwo im Dunkeln rumdüst und völlig überraschend in einer Raumzeit-Anomalie hängt oder von Q für die Verbrechen der Menschheit angeklagt wird.<br />
Aber gerade bei neuen Software-System hat man viele Stellen noch nicht berührt und muss sich häufig auf bereits existierendes Verhalten verlassen, wenn man neue Komponenten integriert. So geschehen heute. Ich möchte kurz vorstellen &#8211; die Aufgabe:</p>
<blockquote><p>Rufe via REST eine URL auf, die den Status einer Entity umsetzt. </p></blockquote>
<p>Zusätzliche Herausforderung: </p>
<blockquote><p>Kann sein, dass die Gegenstelle nicht da ist.</p></blockquote>
<p>Es folgte eine Odyssee von URL-Anpassungen. So mach ich mich daran, den Aufruf zu implementieren und bekomme ein einziges Wort zurück &#8220;<code>StatusNotAllowedException</code>&#8220;. Ich denk mir so: &#8220;Ok, das hört sich doch gut an.&#8221;, da ich wusste, dass die Status-Änderung mit dem aktuellen Objekt wirklich nicht erlaubt bzw. sein sollte. Witzigerweise war aber das Problem, dass ich einen völlig falschen Call getriggert hatte &#8211; klassisch Copy&#038;Paste. Erst nachdem ich verkündete, dass der Aufruf implementiert sei, wurde ich aufgeklärt, dass die Antwort nicht korrekt ist. Nach kurzem scharfen Hinsehen war die URL dann auch schnell ausgetauscht. </p>
<p>Also ging es auf zu Runde 2. Wie bereits angesprochen gab es ja noch die Nebeninfo, dass evtl. die Empfängerstelle noch nicht implementiert ist. Darum gab es auch hier wieder für mich keinen wirklichen Argwohn als die Schnittstelle eine 404 zurücklieferte. Vorgewärmt von der ersten Fehlermeldung hab ich gleich gefragt, ob die Empfängerseite wirklich nicht da sei, worauf ein &#8220;doch, ist da&#8221; zurückgeliefert wurde.<br />
Also schauen wir uns die URL an und entdecken: Oha, die Ports sind falsch. Aber nicht nur bei einer URL, sondern bei allen. Auch das geändert und somit kommen wir zu &#8230;</p>
<p>&#8230; Runde 3: Fehlermeldungen, die nicht da auftauchen wo sie erwartet werden. Leider gab es dann noch einen Schusselfehler bei der Änderung der Ports, so dass ein Aufruf an den alten Port geschickt wurde und mit unverhohlener Freundlichkeit meinte &#8220;kenn ich nicht&#8221;. In meinem Gesicht manifestierte sich die Frage &#8220;was kennst du nicht?&#8221;. In meinem Log tauchte nichts auf, im Log auf dem Server, auf dem wir dachten, dass der Aufruf aufschlagen sollte kam auch nichts. Zwar lag das eigentliche Problem am falschen Port, aber die Fehlermeldung sagte nichts darüber aus, was gerade schief gelaufen ist. Auch im Log des eigentlichen Servers &#8211; da wo der Call gelandet war &#8211; stand nichts aussagekräftiges. Am Ende half nur das 4-Augen-Prinzip um den Fehler zu finden.</p>
<p>Fazit: Ein Hoch auf die verbale Kommunikation und ein leidiges Buh auf schlecht formulierte Fehlermeldungen. Zwar muss man schon einiges an Schusseligkeit an den Tag legen um so viele Fehler hintereinander zu machen &#8211; und es passiert doch &#8211; aber gerade beim Ersten hätte es beinahe dazu geführt, dass ich mich in einer Sicherheit wähnte, die gar nicht da war und die uns im Produktiv-System ggf. teuer hätte zu stehen kommen können. Darum sollten Fehlermeldungen stets so viel Informationen enthalten, dass sie das eigentliche Problem konkret darstellen und entweder mögliche Ursachen oder mögliche Lösungen vorschlagen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pincservices.de/wordpress/trugerische-sicherheit-fehlermeldungen-ohne-kontextinformationen/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Warum &#8220;agile&#8221; nicht immer agil ist &#8230;</title>
		<link>http://www.pincservices.de/wordpress/warum-agile-nicht-immer-agil-ist</link>
		<comments>http://www.pincservices.de/wordpress/warum-agile-nicht-immer-agil-ist#comments</comments>
		<pubDate>Mon, 13 Jun 2011 07:30:33 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Projektverwaltung]]></category>
		<category><![CDATA[agile softwaredevelopment]]></category>
		<category><![CDATA[scrum]]></category>
		<category><![CDATA[scrum smells]]></category>

		<guid isPermaLink="false">http://www.pincservices.de/wordpress/?p=559</guid>
		<description><![CDATA[Nach mehreren Jahren (angeblicher) agiler Softwareentwicklung ist es interessant zu sehen, wie der Begriff &#8220;agile&#8221; gerne zum Motto eines chaotischen und unkoordinierbaren Gewusels werden kann. Aber bevor ich in einen Rausch von Anschuldigungen, Verfluchungen und verzweifelten Rundumschlägen verfalle &#8211; eine kurze Vorstellung von dem was agile Softwareentwicklung leisten soll. Wikipedia beschreibt die Zielsetzung von agiler [...]]]></description>
			<content:encoded><![CDATA[<p>Nach mehreren Jahren (angeblicher) agiler Softwareentwicklung ist es interessant zu sehen, wie der Begriff &#8220;agile&#8221; gerne zum Motto eines chaotischen und unkoordinierbaren Gewusels werden kann. </p>
<p>Aber bevor ich in einen Rausch von Anschuldigungen, Verfluchungen und verzweifelten Rundumschlägen verfalle &#8211; eine kurze Vorstellung von dem was agile Softwareentwicklung leisten soll.<br />
Wikipedia beschreibt die Zielsetzung von agiler Softwareentwicklung wie folgt:</p>
<blockquote><p>Das Ziel Agiler Softwareentwicklung ist es, den Softwareentwicklungsprozess flexibler und schlanker zu machen, als das bei den klassischen Vorgehensmodellen der Fall ist. Man möchte sich mehr auf die zu erreichenden Ziele fokussieren und auf technische und soziale Probleme bei der Softwareentwicklung eingehen. Die Agile Softwareentwicklung ist eine Gegenbewegung zu den oft als schwergewichtig und bürokratisch angesehenen traditionellen Softwareentwicklungsprozessen wie dem Rational Unified Process oder dem V-Modell.</p></blockquote>
<p>Häufig wird sich vor allem auf die ersten beiden Sätze konzentriert, die selbstverständlich eine große Bedeutung haben. Aber aus meiner Sicht hat aber der letzte Satz eine interessante Nebenbedeutung.<br />
Im Folgenden werde ich mich auf die Vorgehensweise nach Scrum konzentrieren, da sie meist als Vorzeige-Prozess verwendet wird und sich viele Firmen dies auf die &#8220;Fahnen&#8221; schreiben.<br />
Agile Softwarentwicklung wird als Gegenbewegung zu bürokratischen Prozessen angesehen. Was hier nur häufig scheinbar hinzugefügt wird, ist das Abschaffen von (notwendigen) formalen Regeln.  </p>
<ul>
<li>So ignoriert man des öfteren, dass ein Sprint in sich unveränderbar ist &#8211; das dies auch legitim sein kann, werde ich gleich erläutern.</li>
<li>Daily Scrums z.B. werden teilweise wie ein Kaffeeklatsch behandelt oder &#8211; noch schlimmer &#8211; werden als Plattform für das Management verwendet um dem Team neue Priorisierungen mitzuteilen.</li>
<li>Beliebt sind auch Sprintplanungen, in denen dem Team vorgeschrieben wird, wieviel Zeit es für welche Aufgaben haben darf.</li>
<li>Teammitglieder erscheinen gar nicht oder zu spät zu Meetings. </li>
<li> Daily Scrums beinhalten entweder zu viele oder zu wenige &#8220;Pigs&#8221; bzw. &#8220;Chickens&#8221; verhalten sich wie &#8220;Pigs&#8221;.</li>
<li>Sprintziele bzw. Commitments werden nicht ernst genommen.</li>
<li>&#8230;</li>
</ul>
<p>Eine kleine Übersicht über Anhaltspunkte, dass es mit dem agilen Prozess nicht ganz so gut bestellt ist, gibt folgende Seite über <a href="http://scrumcommunity.pbworks.com/w/page/10149004/Scrum-Smells">Scrum-Smells</a>.</p>
<p>Die Konsequenzen, wenn der &#8220;Gestank&#8221; (dt. für Smell) nicht berücksichtigt wird, sind einerseits lange Entwicklungszeiten und häufige Wartungsaktionen, da die Anforderungen nicht klar waren/sind oder Aufgaben permanent verschoben werden und andererseits Versuche Probleme mit klassisch bürokratischen Mitteln zu kompensieren, wie minutiös ausgearbeiteten Konzepten. Dadurch verlangsamt sich zusehends und dramatisch die Entwicklungszeit und damit die Reaktionszeit auf Kundenwünsche und Bugs. Ebenso wird die Flexibilität des Teams auf die reine Programmierung reduziert, die dann ggf. noch durch (von sich selbst übermäßig überzeugte) Code-Reviewer ad absurdum geführt wird.</p>
<p>Da dies kein komplettes Buch über die Vor- und Nachteile von Scrum respektive agiler Softwareentwicklung werden soll, möchte ich nur Folgendes festhalten:</p>
<p>Agile Softwareentwicklung besitzt genausoviel oder teils sogar mehr Formalismus als klassische Softwareentwicklung. Allerdings wird versucht den bürokratischen Aufwand zu reduzieren. Agil heisst hier vor allem, dass das Team wesentlich flexibler agieren und reagieren kann, als es in klassischen Prozessen ist und nicht, dass die Aufgabenstellung beliebig agil geändert werden kann. Dieser erhöhte Formalismus bedarf aber ebenso einer durchgängigen Disziplin aller Beteiligten. Ist diese Disziplin gegeben lassen sich auch innerhalb einer Iteration die Anforderungen bis zu einem bestimmten Grad ändern. Falls nicht, ist davon &#8211; wie es im Allgemeinen in der Literatur vorgegeben ist &#8211; abzuraten.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pincservices.de/wordpress/warum-agile-nicht-immer-agil-ist/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java + Groovy: Sample-Project PdfRenderer auf Github</title>
		<link>http://www.pincservices.de/wordpress/java-groovy-sample-project-pdfrenderer-auf-github</link>
		<comments>http://www.pincservices.de/wordpress/java-groovy-sample-project-pdfrenderer-auf-github#comments</comments>
		<pubDate>Wed, 29 Dec 2010 18:46:13 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Groovy]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Projekte]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[html2pdf]]></category>
		<category><![CDATA[pdf]]></category>
		<category><![CDATA[pdfrenderer]]></category>
		<category><![CDATA[renderer]]></category>

		<guid isPermaLink="false">http://www.pincservices.de/wordpress/?p=545</guid>
		<description><![CDATA[Das Buch &#8220;Groovy in Action&#8221; führt den Begriff &#8220;Beauty through Brevity&#8221; ins Feld, der auch gern in Verbindung mit Scala oder Clojure einhergeht. Lässt man diese Sprachen für sich alleine mag das auch gelten, doch für viele Entwicklungen, die noch mit älterem Java-Code arbeiten, ist es wichtig, dass die Kombination verschiedener Sprachen ein stimmiges Gesamtbild [...]]]></description>
			<content:encoded><![CDATA[<p>Das Buch &#8220;Groovy in Action&#8221; führt den Begriff &#8220;Beauty through Brevity&#8221; ins Feld, der auch gern in Verbindung mit Scala oder Clojure einhergeht. Lässt man diese Sprachen für sich alleine mag das auch gelten, doch für viele Entwicklungen, die noch mit älterem Java-Code arbeiten, ist es wichtig, dass die Kombination verschiedener Sprachen ein stimmiges Gesamtbild abgibt &#8211; und hier lauern gern die ein oder anderen Stolperdrähte.</p>
<p>Unter <a href="https://github.com/Zigu/PdfRenderer">https://github.com/Zigu/PdfRenderer</a> habe ich ein älteres Projekt von mir in ein neues &#8220;Misch-Gewand&#8221; geworfen und geschaut ob es funktioniert. Und ja, das tut es &#8211; mit Einschränkungen.</p>
<p>Grundsätzlich kann man sagen, dass die Kombination Maven2 + Java + Groovy eine sehr angenehme Sache ist, wenngleich der Weg dorthin etwas dornig war. Insbesondere durch die maßlos veraltete Dokumentation von GMaven &#8211; ich verzichte bewusst auf eine Verlinkung &#8211; wodurch nicht klar war, wie einfach es eigentlich ist Maven dazu zu bringen auch Groovy-Code zu verarbeiten.</p>
<p>Vorsicht ist allerdings geboten beim Einsatz von Closures in Vererbungshierarchien. Es gibt in Groovy 1.7.6 noch ein Problem, wenn eine konkrete Kindklasse aufgerufen wird, deren abstrakte Oberklasse ein Closure enthält, dass private Felder dieser Elternklasse verwendet. Eine kurze Skizzierung des Problems:</p>
<pre class="brush: plain;">
abstract class A {
  private List _myList;
  private ListElementHandler _handler;

  public void handleList() {
    _myList.each{ _handler.do_something_with(it) }
  }
}

class B extends A { ... }

class C {
  public void call() {
    def b = new B()
    b.handleList()
  }
}
</pre>
<p>Leider kommt es im Zuge des Abarbeitung der Klasse C zu einer Exception, dass das Feld <code>_handler</code> nicht zur Klasse B gehört. Dieses Problem ist bereits in den Groovy-Bugtracker aufgenommen worden.</p>
<p>Trotz dieser kleineren Hürden, verlief die Umstrukturierung ziemlich glatt und am Ende entstand größtenteils ein stimmiges Gesamtbild mit einigen sehr angenehmen &#8220;Abkürzungen&#8221; dank Groovy.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pincservices.de/wordpress/java-groovy-sample-project-pdfrenderer-auf-github/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Erster Blick auf GWT 2.1.1 Requestfactory</title>
		<link>http://www.pincservices.de/wordpress/erster-blick-auf-gwt-2-1-1-requestfactory</link>
		<comments>http://www.pincservices.de/wordpress/erster-blick-auf-gwt-2-1-1-requestfactory#comments</comments>
		<pubDate>Thu, 16 Dec 2010 06:11:43 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Webentwicklung]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[RequestFactory]]></category>
		<category><![CDATA[servicelocator]]></category>

		<guid isPermaLink="false">http://www.pincservices.de/wordpress/?p=532</guid>
		<description><![CDATA[Vor einigen Tagen wurde der erste Release-Kandidat for GWT 2.1.1 veröffentlicht. Was dieser enthält kann man hier nachlesen. Nachdem ich bereits über einen Workaround für GWT 2.1 bezüglich des RequestFactory-Einsatzes mit Spring gesprochen habe war für mich vor allem das neue RequestFactory-API interessant. Dieses hat jetzt in u.a. in der Service-Annotation einen locator mit dem [...]]]></description>
			<content:encoded><![CDATA[<p>Vor einigen Tagen wurde der erste Release-Kandidat for GWT 2.1.1 veröffentlicht. Was dieser enthält kann man <a href="http://groups.google.com/group/google-web-toolkit/browse_thread/thread/6f2418947d7efeb9">hier</a> nachlesen.</p>
<p>Nachdem ich <a href="http://www.pincservices.de/wordpress/statische-schl…ory-mit-spring">bereits</a> über einen Workaround für GWT 2.1 bezüglich des RequestFactory-Einsatzes mit Spring gesprochen habe war für mich vor allem das neue RequestFactory-API interessant. Dieses hat jetzt in u.a. in der Service-Annotation einen <code>locator</code> mit dem man auf Klassen referenzieren kann, die keine statischen Methoden enthalten. Ein schönes Beispiel für den Einsatz findet sich in der GWT Google Group (<a href="https://groups.google.com/group/google-web-toolkit/browse_thread/thread/20ea2aea53aa29d3">zugehöriger Thread</a>).</p>
<p>Der folgende Auszug ist aus dem eben genannten Thread.</p>
<pre class="brush: java;">
public class SpringServiceLocator implements ServiceLocator {
        @Override
        public Object getInstance(Class&lt;?&gt; clazz) {
                HttpServletRequest request = RequestFactoryServlet.getThreadLocalRequest();
                ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(request.getSession().ge tServletContext());
                return context.getBean(clazz);
        }
}
</pre>
<p>&#8220;I annotate my RequestContext with the GWT @Service annotation (not the<br />
Spring one). Example below:&#8221;</p>
<pre class="brush: java;">
@Service(locator = SpringServiceLocator.class, value =
AddressService.class)
public interface AddressRequest extends RequestContext {
        // Get address by id
        Request&lt;AddressProxy&gt; get(Long id);
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.pincservices.de/wordpress/erster-blick-auf-gwt-2-1-1-requestfactory/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Clean Code und Refactoring &#8211; Das riecht aber komisch</title>
		<link>http://www.pincservices.de/wordpress/clean-code-und-refactoring-das-riecht-aber-komisch</link>
		<comments>http://www.pincservices.de/wordpress/clean-code-und-refactoring-das-riecht-aber-komisch#comments</comments>
		<pubDate>Tue, 07 Dec 2010 23:17:51 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Softwaredesign]]></category>
		<category><![CDATA[clean code]]></category>
		<category><![CDATA[patterns]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[refactoring]]></category>

		<guid isPermaLink="false">http://www.pincservices.de/wordpress/?p=471</guid>
		<description><![CDATA[Wer sich schonmal über einen Quellcode gesetzt hat &#8211; über den eigenen oder eines anderen Entwicklers &#8211; und sich nach kurzer Zeit gefühlt hat, er müsse mal kurz weggehen um frische Luft zu bekommen, der hat es wohl mit einem sogenannten &#8220;Code smell&#8221; zu tun. &#8220;Code smell&#8221; ist ein Begriff, dem man &#8211; je länger [...]]]></description>
			<content:encoded><![CDATA[<p>Wer sich schonmal über einen Quellcode gesetzt hat &#8211; über den eigenen oder eines anderen Entwicklers &#8211; und sich nach kurzer Zeit gefühlt hat, er müsse mal kurz weggehen um frische Luft zu bekommen, der hat es wohl mit einem sogenannten &#8220;Code smell&#8221; zu tun. </p>
<p>&#8220;Code smell&#8221; ist ein Begriff, dem man &#8211; je länger man in der Softwareentwicklung unterwegs ist &#8211; mittlerweile kaum noch entgehen kann. Sei es nun im eigenen Projekt oder in der aktuellen Fachpresse. Für jene, denen dieser Begriff noch nicht geläufig ist, sei er wie folgt kurz erklärt:</p>
<p>Ein &#8220;Code smell&#8221; ist ein Symptom für tieferliegende Programm-Probleme, das sich durch unschönen bzw. verwirrenden Quellcode zeigt.</p>
<p>Eine konkretere Herleitung findet sich u.a. auf der entsprechenden <a href="http://en.wikipedia.org/wiki/Code_smell">Wikipedia-Seite</a>. Wie die obige Erklärung bereits andeutet sind Code smells eine relativ subjektive Angelegenheit. Wann ist eine Methode zu lang, oder was sind angemessene Variablenbezeichner? Eine Antwort auf diese Fragen muss man am Ende vor allem für sich selbst finden.<br />
Was ist jedoch zu tun, wenn man über solchen Code stolpert? Wie schreibe ich z.B. eine Methodensignatur so um, dass ich sicher sein kann, dass mein Code immer noch wie vorher funktioniert? Hierfür möchte ich 3 Bücher vorstellen, die man getrost als Leitfaden für Erkennung, Vermeidung und Aufräumaktionen verwenden kann.</p>
<div style="float:left; display: block; margin-bottom: 10px;">
<img class="wp-image-481" title="Clean Code" src="http://www.pincservices.de/wordpress/wp-content/uploads/2010/12/cc_bookReview_CleanCode.jpg" alt="" width="150" align="left" hspace="10"/> Clean Code stellt viele Aspekte für unschönen Code vor, die man bei der täglichen Arbeit zwar bemerkt, aber bei denen man unter Umständen nicht immer weiss wie man sie besser machen kann. Der Autor gibt sich hierbei nicht den Anspruch des allumfassenden &#8220;So-und-nicht-anders&#8221;, sondern lässt Freiraum für eigene Entscheidungen.
</div>
<div style="float:left; display: block; margin-bottom: 10px;">
<img class="wp-image-479" title="Refactoring" src="http://www.pincservices.de/wordpress/wp-content/uploads/2010/12/refactoring_book.png" alt="" width="150" align="left" hspace="10" /> Martin Fowler stellt verschiedene Refactoring-Mechanismen vor und erklärt die Motivation, die hinter jedem einzelnen steckt. Da es sich hierbei u.a. auch um sehr triviale Refactorings handelt, wirkt das Buch zeitweise etwas trocken.<br />
Dies wird jedoch durch die Darstellung verschiedener &#8220;Bad smells in Code&#8221; teilweise wieder ausgeglichen.
</div>
<div style="float: left; display: block;">
<img class="wp-image-480" title="Refactoring to Patterns" src="http://www.pincservices.de/wordpress/wp-content/uploads/2010/12/rtp.jpg" alt=""  width="150" align="left" hspace="10" /> Ähnlich aufgebaut wie das &#8220;Refactoring&#8221;-Buch werden hier verschiedene Code-Probleme anhand einfacher Beispiele erklärt und deren Lösung durch Patterns oder in Richtung eines Patterns vorgestellt.
</div>
<div style="clear:both;"></div>
<p>Wer sich etwas konkreter mit Refactoring an sich beschäftigten will, seien diese Bücher ans Herz gelegt. Wer meint, er schreibe bereits guten Code, möge folgenden Auszug aus &#8220;Clean Code&#8221; selbst prüfen: Guten Code erkennt man an der Metrik der WTF/minute eines Code Reviewers.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pincservices.de/wordpress/clean-code-und-refactoring-das-riecht-aber-komisch/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Statische Schleusen &#8211; GWT 2.1 RequestFactory mit Spring</title>
		<link>http://www.pincservices.de/wordpress/statische-schleusen-gwt-2-1-requestfactory-mit-spring</link>
		<comments>http://www.pincservices.de/wordpress/statische-schleusen-gwt-2-1-requestfactory-mit-spring#comments</comments>
		<pubDate>Fri, 26 Nov 2010 15:01:48 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Webentwicklung]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[RequestFactory]]></category>
		<category><![CDATA[Spring]]></category>

		<guid isPermaLink="false">http://www.pincservices.de/wordpress/?p=456</guid>
		<description><![CDATA[Manchmal ist Vorfreude die schönste Freude, aber wenn die Vorfreude die einzige Freude ist, dann stimmt etwas nicht. So auch bei den heißersehnten RequestFactories von GWT 2.1. In Erwartung, dass damit der Zugriff auf Domain-Objekte/Entities stark vereinfacht werden soll, kam es &#8211; zumindest bei mir &#8211; zu einem jähen Erwachen, nachdem ich versuchte die RequestFactory [...]]]></description>
			<content:encoded><![CDATA[<p>Manchmal ist Vorfreude die schönste Freude, aber wenn die Vorfreude die einzige Freude ist, dann stimmt etwas nicht. So auch bei den heißersehnten RequestFactories von GWT 2.1. In Erwartung, dass damit der Zugriff auf Domain-Objekte/Entities stark vereinfacht werden soll, kam es &#8211; zumindest bei mir &#8211; zu einem jähen Erwachen, nachdem ich versuchte die RequestFactory auf ein Service-Klasse verweisen zu lassen, die von Spring verwaltet wird.</p>
<p>Die Entwickler der RequestFactory haben sich nämlich ein schönes Konstrukt in der Klasse <code>ReflectionBasedOperationRegistry</code> ausgedacht, welches es nur gestattet entweder statische Methode oder eine Methode der Entity selbst aufzurufen.</p>
<pre class="brush: java; wrap-lines: false;">
boolean isInstance = InstanceRequest.class.isAssignableFrom(requestMethod.getReturnType());
if (isInstance == Modifier.isStatic(domainMethod.getModifiers())) {
  throw new IllegalArgumentException(&quot;domain method &quot; + domainMethod
          + &quot; and interface method &quot; + requestMethod
          + &quot; don't match wrt instance/static&quot;);
}
</pre>
<p>Zur allgemeinen Verteidigung: in der kommenden Version GWT 2.1.1 wurde diese Einschränkung angeblich schon ausgebaut. Da zum aktuellen Zeitpunkt allerdings nicht klar ist, wann diese Version veröffentlicht wird, muss man sich mit anderen Mitteln behelfen. Eines dieser Mittel möchte ich kurz vorstellen.</p>
<p>Die Idee hinter dem ganzen ist es einen Adapter zu schreiben, der die notwendigen statischen Methoden für die RequestFactory bereitstellt und diese an den eigentlichen Service delegiert.<br />
Ich gehe davon aus, dass der Leser mit dem Grundprinzip der GWT RequestFactory vertraut ist. Falls nicht, empfehle ich einen Blick auf <a href="http://code.google.com/intl/de-DE/webtoolkit/doc/latest/DevGuideRequestFactory.html">diese Seite</a>.</p>
<p>Als Erstes möchte ich die RequestFactory vorstellen:</p>
<pre class="brush: java; wrap-lines: false;">
public interface SampleRequestFactory extends RequestFactory {

    @Service(SampleRequestAdapter.class)
    interface SampleRequestContext extends RequestContext {
        Request&lt;List&lt;SampleEntityProxy&gt;&gt; findAll();
    }

    SampleRequestContext sampleRequestContext();
}
</pre>
<p>Für diejenigen, die sich mit Spring auskennen sei darauf hingewiesen, dass die obige <code>Service</code>-Annotation nicht die von Spring, sondern die von GWT ist.</p>
<p>Weiter im Text &#8230;</p>
<p>Der entsprechende Adapter könnte in etwa so aussehen.</p>
<pre class="brush: java; wrap-lines: false;">
public class SampleRequestAdapter {

    private static SampleService _sampleService;

    public static void setApplicationContext(ApplicationContext applicationContext) {
        _sampleService = applicationContext.getBean(SampleService.class);
    }

    public static List&lt;SampleEntity&gt; findAll() {
        return _sampleService.findAll();
    }
}
</pre>
<p>Soweit, sogut. Bisher ist noch nichts Spannendes passiert. Dennoch ist die Luft bereits erfüllt mit &#8220;Entwickler-Magie&#8221;. Die offene Frage ist nämlich: Wie wird die Methode <code>setApplicationContext()</code> aufgerufen?</p>
<p>Die Lösung ist zwar nicht zwingend schön, aber wirkungsvoll:</p>
<ul>
<li>Man nehme eine Klasse, die von Spring verwaltet wird.</li>
<li>Mache diese Klasse <code>ApplicationContextAware</code>.</li>
<li>Gebe dieser Klasse die Adapter als Parameter und rufe für alle die Setter-Methode auf.</li>
</ul>
<p>Im Code-Gewand sähe dies so aus:</p>
<pre class="brush: java; wrap-lines: false;">
public class ApplicationContextProvider implements ApplicationContextAware {
    private List&lt;Class&gt; _requestAdapters;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (_requestAdapters != null) {
            for (Class requestAdapter : _requestAdapters) {
                try {
                    final Method setter = requestAdapter.getDeclaredMethod(&quot;setApplicationContext&quot;, ApplicationContext.class);
                    if (Modifier.isStatic(setter.getModifiers())) {
                        setter.invoke(requestAdapter, applicationContext);
                    }
                // ... exception handling code
            }
        }
    }

    public List&lt;Class&gt; getRequestAdapters() {
        return _requestAdapters;
    }

    public void setRequestAdapters(List&lt;Class&gt; requestAdapters) {
        _requestAdapters = requestAdapters;
    }
}
</pre>
<p>Abschließend muss der Provider selbstverständlich noch für Spring verfügbar gemacht werden.</p>
<pre class="brush: xml;">
&lt;bean class=&quot;de.sampleproject.ApplicationContextProvider&quot;&gt;
  &lt;property name=&quot;requestAdapters&quot;&gt;
    &lt;list&gt;
      &lt;value&gt;de.sampleproject.SampleRequestAdapter&lt;/value&gt;
    &lt;/list&gt;
  &lt;/property&gt;
&lt;/bean&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.pincservices.de/wordpress/statische-schleusen-gwt-2-1-requestfactory-mit-spring/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Griffon: Mit einem “Flügelschlag” außer Gefecht gesetzt</title>
		<link>http://www.pincservices.de/wordpress/griffon-mit-einem-flugelschlag-auser-gefecht-gesetzt</link>
		<comments>http://www.pincservices.de/wordpress/griffon-mit-einem-flugelschlag-auser-gefecht-gesetzt#comments</comments>
		<pubDate>Thu, 04 Mar 2010 19:20:28 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[griffon]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://www.pincservices.de/wordpress/?p=438</guid>
		<description><![CDATA[Es gibt ein Sprichwort: &#8220;Kleinchen heb die Beinchen jetzt kommen Steinchen&#8221;. So geschehen bei mir, als ich das erste Mal Griffon unter Windows ausprobieren wollte. Es ließ sich Partout nicht starten und belegte mich mit der Meldung, dass meine &#8220;JAVA_HOME&#8221;-Variable auf ein invalides Verzeichnis verweisen würde. Leider konnte ich auf dem System nicht die JAVA_HOME [...]]]></description>
			<content:encoded><![CDATA[<p>Es gibt ein Sprichwort: &#8220;Kleinchen heb die Beinchen jetzt kommen Steinchen&#8221;. So geschehen bei mir, als ich das erste Mal Griffon unter Windows ausprobieren wollte.</p>
<p>Es ließ sich Partout nicht starten und belegte mich mit der Meldung, dass meine &#8220;JAVA_HOME&#8221;-Variable auf ein invalides Verzeichnis verweisen würde. Leider konnte ich auf dem System nicht die JAVA_HOME direkt ändern, sondern musste diese in den Umgebungsvariablen des Benutzers &#8220;überschreiben&#8221;. Ist dann schon etwas unschön, aber gut &#8211; es ging erstmal ans Werk.</p>
<p>Nun ist man ja als alteingesessener Java-Entwickler daran gewöhnt, dass Pfade mit Leerzeichen nie gut ankommen. Also 1. Versuch: Leerzeichen entfernen &#8211; Kein Erfolg. Einmal ist keinmal, also nächster Versuch: Suchmaschine bemühen &#8211; wenig Erfolg. </p>
<p>Die Suche gab zwar nicht die vollständige Antwort, aber zumindest einen Anhaltspunkt. Der abschließende Backslash im Pfad könnte ein Problem sein. Zwar führte dieser Ansatz erstmal zu einem gewissen Erfolg, aber einfach mal eine Systemvariable überschreiben &#8211; auch wenn es nicht so große Unterschiede gab &#8211; fand ich nicht so &#8220;prickelnd&#8221;. Darum kam am Ende der Texteditor zum Einsatz, denn mir war aufgefallen, dass Groovy selbst z.B. keine Probleme mit dem Pfad hatte.</p>
<p>Und da war sie &#8211; die Lösung, die ich gesucht hatte:</p>
<pre class="brush: plain;">
@rem Remove trailing slash from JAVA_HOME if found
if &quot;%JAVA_HOME:~-1%&quot;==&quot;\&quot; SET JAVA_HOME=%JAVA_HOME:~0,-1%
</pre>
<p>Mit dieser Zeile wird einfach das abschließende Backslash entfernt. Diese Zeile in die <code>startGriffon.bat</code> unter <code>:have_JAVA_HOME</code> geschrieben und plötzlich funktioniert es auch mit dem Greif.</p>
<pre class="brush: plain;">
:have_JAVA_HOME
if &quot;%JAVA_HOME:~-1%&quot;==&quot;\&quot; SET JAVA_HOME=%JAVA_HOME:~0,-1%
@rem Validate JAVA_HOME
%COMMAND_COM% /C DIR &quot;%JAVA_HOME%&quot; 2&gt;&amp;1 | %FIND_EXE% /I /C &quot;%JAVA_HOME%&quot; &gt;nul
</pre>
<p>Leider wurde das Problem auch in der aktuellen Version 0.3 nicht gefixt.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pincservices.de/wordpress/griffon-mit-einem-flugelschlag-auser-gefecht-gesetzt/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Trac-Themes</title>
		<link>http://www.pincservices.de/wordpress/trac-themes</link>
		<comments>http://www.pincservices.de/wordpress/trac-themes#comments</comments>
		<pubDate>Thu, 28 Jan 2010 21:38:12 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Projektverwaltung]]></category>
		<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[Werkzeuge]]></category>
		<category><![CDATA[htdocs_location]]></category>
		<category><![CDATA[Templates]]></category>
		<category><![CDATA[themes]]></category>
		<category><![CDATA[Trac]]></category>

		<guid isPermaLink="false">http://www.pincservices.de/wordpress/?p=410</guid>
		<description><![CDATA[2 Jahre ist es jetzt in etwa her, dass ich einen Artikel über Eigene Templates in Trac geschrieben habe. Seitdem ist ein wenig passiert. Diesen Änderungen möchte ich hiermit Rechnung tragen. Ich habe das ganze Trac-Themes genannt, weil es weniger um Templating an sich gehen soll, sondern eher um eine Möglichkeit gemeinsame Styles festlegen zu [...]]]></description>
			<content:encoded><![CDATA[<p>2 Jahre ist es jetzt in etwa her, dass ich einen Artikel über <a href="http://www.pincservices.de/wordpress/eigene-templates-in-trac">Eigene Templates in Trac</a> geschrieben habe. Seitdem ist ein wenig passiert. Diesen Änderungen möchte ich hiermit Rechnung tragen. Ich habe das ganze Trac-Themes genannt, weil es weniger um Templating an sich gehen soll, sondern eher um eine Möglichkeit gemeinsame Styles festlegen zu können.</p>
<p>Leider ist es mit Trac immer noch nicht möglich unter einem Environment mehrere Projekte bzw. Repositories laufen zu lassen. Darum wird für jedes Projekt eine eigene Trac-Umgebung angelegt. Wichtig hierbei ist insbesondere für Firmen, dass alle Projekte zumindest in der Grundstruktur gleich aussehen und die Firmenfarben tragen.</p>
<h3>&#8220;&#8230; was bisher geschah&#8221;</h3>
<p>Wer zuerst probieren will, wie und was er alles anpassen kann, sollte sich das Verzeichnis <code>templates</code> unterhalb seiner Trac-Umgebung anschauen. Standardmäßig liegt dort die Datei <code>site.html</code>. Wenn man sie das erste Mal aufmacht, kommt sie sehr unscheinbar daher, denn wie man sieht, sieht man nichts. Nur einen <code>html</code>-Tag und ein paar unbekannt anmutende Python-Attribute.<br />
Auf der Seite <a href="http://trac.edgewall.org/wiki/TracInterfaceCustomization">http://trac.edgewall.org/wiki/TracInterfaceCustomization</a> ist glücklicherweise bereits ein Beispiel-Code für den Inhalt dieser Datei. Für jene, die gerne lieber mehrere Dateien nutzen wollen hier gleich die Anpassung mit Einbindung externer Dateien:</p>
<pre class="brush: xml;">
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;
      xmlns:py=&quot;http://genshi.edgewall.org/&quot;
      xmlns:xi=&quot;http://www.w3.org/2001/XInclude&quot;
      py:strip=&quot;&quot;&gt;

  &lt;!--! Add site-specific style sheet --&gt;
  &lt;head py:match=&quot;head&quot; py:attrs=&quot;select('@*')&quot;&gt;
    ${select('*|comment()|text()')}
    &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot;
          href=&quot;${href.chrome('common/style.css')}&quot; /&gt;
  &lt;/head&gt;

  &lt;body py:match=&quot;body&quot; py:attrs=&quot;select('@*')&quot;&gt;
    &lt;!--! Add site-specific header --&gt;
    &lt;div id=&quot;siteheader&quot;&gt;
       &lt;xi:include href=&quot;site_header.cs&quot;&gt;
         &lt;xi:fallback /&gt;
       &lt;/xi:include&gt;
    &lt;/div&gt;

    ${select('*|text()')}

    &lt;!--! Add site-specific footer --&gt;
    &lt;div id=&quot;sitefooter&quot;&gt;
      &lt;xi:include href=&quot;site_footer.cs&quot;&gt;
        &lt;xi:fallback /&gt;
      &lt;/xi:include&gt;
    &lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Interessanterweise funktioniert das einfache Anlegen einer <code>site_header.cs</code> und <code>site_footer.cs</code> nicht immer &#8211; bzw. bei mir hat das noch nie funktioniert -, wie es auf manchen Seiten beschrieben wird.<br />
Mit diesem Grundgerüst ausgestattet lässt sich schon anfangen herumzuspielen. Für weiterführende Informationen zu Genshi und Clearsilver &#8211; den Engines im Hintergrund &#8211; sei auf folgende Seiten verwiesen:</p>
<ul>
<li><a href="http://genshi.edgewall.org/">http://genshi.edgewall.org/</a></li>
<li><a href="http://www.clearsilver.net/docs/">http://www.clearsilver.net/docs/</a></li>
</ul>
<h3>Neue und alte Freunde</h3>
<p>Ein altbekannter Helfer beim Erstellen von Templates ist auch in der Version 0.11.5 noch vorhanden. Der Konfigurationsparameter <code>template_dir</code>.</p>
<pre class="brush: plain;">
[inherit]
template_dir=
</pre>
<p>Mit diesem Parameter lässt sich das Verzeichnis für die Templates festlegen und wodurch verschiedene Seiten mit ein und demselben Template ausgestattet werden können.</p>
<p>Daneben ist ein neuer Freund dazugekommen der Parameter <code>htdocs_location</code>. Mit diesem Parameter werden alle internen URLs, die mit &#8220;common/&#8221; beginnen in die URL umgeschrieben, die als Wert angegeben wurde.</p>
<pre class="brush: plain;">
[trac]
htdocs_location=http://localhost/mytemplate
</pre>
<p>Führt, dazu, dass aus</p>
<pre class="brush: xml; gutter: false;">
&lt;link rel=&quot;stylesheet&quot; href=&quot;/trac/templating/chrome/common/css/trac.css&quot; type=&quot;text/css&quot; /&gt;
</pre>
<p>folgendes wird</p>
<pre class="brush: xml; gutter: false;">
&lt;link rel=&quot;stylesheet&quot; href=&quot;http://localhost/mytemplate/css/trac.css&quot; type=&quot;text/css&quot; /&gt;
</pre>
<p><strong>Achtung!</strong> Leider hat die Sache einen Haken. Eigene Links aus der <code>site.html</code> werden nicht übersetzt. Der folgende Code</p>
<pre class="brush: plain; gutter: false;">
${href.chrome('common/style.css')}
</pre>
<p>wird nur in <code>"/trac/templating/chrome/common/style.css"</code> umgewandelt, aber nicht weiter.</p>
<p>Wichtig ist außerdem zu beachten, dass <code>htdocs_location</code> nur für statische Inhalte, wie Bilder, JavaScript- und CSS-Dateien gedacht ist. Templates werden nicht automatisch von dort erkannt. Diese müssen explizit über <code>template_dir</code> konfiguriert werden. Leider ist es hier nur möglich lokale Verzeichnisse zu setzen. Wer z.B. versucht eine Internetadresse anzugeben, bekommt zwar keine Fehlermeldung, wird aber mit einem Standard-Template &#8220;belohnt&#8221;.</p>
<p>Abschließend möchte ich sagen, dass &#8211; gefühlt &#8211; wesentlich mehr über die <code>trac.ini</code> konfigurierbar ist, als es noch vor 2 Jahren der Fall war. Das macht definitiv Lust auf mehr, aber dennoch bleibt das ein oder andere noch zu tun.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pincservices.de/wordpress/trac-themes/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Recipe: Apache 2 mit Tomcat 6 auf Ubuntu 9.10 für &#8220;Gourmets&#8221;</title>
		<link>http://www.pincservices.de/wordpress/recipe-apache-2-mit-tomcat-6-auf-ubuntu-9-10-fur-gourmets</link>
		<comments>http://www.pincservices.de/wordpress/recipe-apache-2-mit-tomcat-6-auf-ubuntu-9-10-fur-gourmets#comments</comments>
		<pubDate>Sat, 23 Jan 2010 10:43:11 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[mod_jk]]></category>
		<category><![CDATA[tomcat]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://www.pincservices.de/wordpress/?p=395</guid>
		<description><![CDATA[Das folgende Thema wurde schon an diversen Stellen mehr oder minder explizit beschrieben. Allerdings noch nicht aus meiner Sicht. Was mir bei den meisten Howtos aufgefallen ist, dass sie schlechte Wartbarkeit hervorrufen und/oder irgendwas vergessen. Darum jetzt mein Versuch die Konfigurationsdateien der Welt unlesbar zu machen. Die &#8220;Speisekarte&#8221; oder &#8220;Was will ich eigentlich&#8221;? Tja. Für den [...]]]></description>
			<content:encoded><![CDATA[<p>Das folgende Thema wurde schon an diversen Stellen mehr oder minder explizit beschrieben. Allerdings noch nicht aus meiner Sicht.</p>
<p>Was mir bei den meisten Howtos aufgefallen ist, dass sie schlechte Wartbarkeit hervorrufen und/oder irgendwas vergessen. Darum jetzt mein Versuch die Konfigurationsdateien der Welt unlesbar zu machen.</p>
<h2>Die &#8220;Speisekarte&#8221; oder &#8220;Was will ich eigentlich&#8221;?</h2>
<p>Tja. Für den einen oder anderen gezielten Sucher ist das schon klar, aber nochmal kurz für jene, die nur zufällig hier sind. Ich möchte in meiner URL nicht mehr <em>http://localhost:8080</em> eingeben müssen um auf meinen Tomcat zu gelangen, sondern nur noch sowas wie <em>http://tomcat.localhost</em>. Ich hätte jetzt auch sagen können <em>http://localhost</em>, aber das wäre gelogen.</p>
<h2>Installation der einzelnen Komponenten</h2>
<p>Für die Installation nehme man eine Maus, Synaptic Paketverwaltung und zwei aussagekräftige Suchbegriffe wie tomcat6 und apache2. Für die Verknüpfung der beiden ist dann noch das Paket <code>libapache2-mod-jk</code> notwendig. Man würze das ganze mit einer Prise &#8220;Anwenden&#8221; und violá Apache 2 und Tomcat 6 sind installiert. Auf zu Schritt 2: die Dateien.</p>
<h2>Die Dateien</h2>
<p>Nichts läuft ohne eine anständige Konfiguration. Zur Vorbereitung lege man sich im Editor seiner Wahl folgende Dateien zurecht. Am besten mit <strong>sudo</strong> öffnen um darauf auch Schreibrechte zu haben.</p>
<ul>
<li>/etc/apache2/sites-available/default</li>
<li>/etc/apache2/sites-available/mod_jk_vhosts</li>
<li>/etc/apache2/mods-available/jk.conf</li>
<li>/etc/apache2/workers.properties</li>
<li>/etc/tomcat6/server.xml</li>
<li>/etc/hosts</li>
</ul>
<p>Die Dateien <code>mod_jk_vhosts</code>, <code>jk.conf</code> und <code>workers.properties</code> existieren höchstwahrscheinlich noch nicht. Darum diese bitte selbst anlegen.</p>
<p>Soweit diese &#8220;Vorspeise&#8221; abgeschlossen ist, wollen wir uns dem &#8220;Hauptgang&#8221; widmen: der Konfiguration</p>
<h2>Die Konfiguration</h2>
<p>Für die Konfiguration gehe ich jede der oben genannten Dateien einzeln durch und stelle eine mögliche Konfiguration vor. Diese Konfigurationen sind nur auf das notwendigste beschränkt. Falls weitere Optionen oder Alternativen notwendig sind, verweise ich gerne auf die entsprechenden Fachseiten.</p>
<h3>mod_jk_vhost</h3>
<p>Beginnen möchte ich mit der <code>mod_jk_vhosts</code>, da diese am umfangreichsten ist. Ich präsentiere &#8230; den Inhalt:</p>
<pre class="brush: plain;">
ServerName localhost
# NameVirtualHost *:80
&lt;VirtualHost *:80&gt;
	ServerName 127.0.0.2
	ServerAlias tomcat.localhost
	ServerAlias www.tomcat.localhost
	ServerAdmin webmaster@tomcat.localhost
	#Take note of the jsp content directory placement
	DocumentRoot /var/lib/tomcat6/webapps/
	&lt;Directory &quot;/var/lib/tomcat6/webapps/&quot;&gt;
		Options Indexes FollowSymLinks +Includes
		AllowOverride All
		# DirectoryIndex index.jsp
	&lt;/Directory&gt;
	#Mount the folders with jsp pages
	JkMount /* worker1
&lt;/VirtualHost&gt;

&lt;VirtualHost *:80&gt;
	ServerName 127.0.0.3
	ServerAlias apache.localhost
	ServerAlias www.apache.localhost
	ServerAdmin webmaster@apache.localhost

	DocumentRoot /var/www
	&lt;Directory /&gt;
		Options FollowSymLinks
		AllowOverride None
	&lt;/Directory&gt;
	&lt;Directory /var/www/&gt;
		Options Indexes FollowSymLinks MultiViews
		AllowOverride None
		Order allow,deny
		allow from all
	&lt;/Directory&gt;

	ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
	&lt;Directory &quot;/usr/lib/cgi-bin&quot;&gt;
		AllowOverride None
		Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
		Order allow,deny
		Allow from all
	&lt;/Directory&gt;

	ErrorLog /var/log/apache2/error.log

	# Possible values include: debug, info, notice, warn, error, crit,
	# alert, emerg.
	LogLevel warn

	CustomLog /var/log/apache2/access.log combined

    Alias /doc/ &quot;/usr/share/doc/&quot;
    &lt;Directory &quot;/usr/share/doc/&quot;&gt;
	Options Indexes MultiViews FollowSymLinks
	AllowOverride None
	Order deny,allow
	Deny from all
	Allow from 127.0.0.0/255.0.0.0 ::1/128
    &lt;/Directory&gt;
&lt;/VirtualHost&gt;
</pre>
<p>Diese Datei wird anstelle der <code>/etc/apache2/sites-available/default</code> zukünftig für die Konfiguration des Apaches verwendet. Darum enthält sie auch große Teile der Original-Datei. Wenn der Inhalt der <code>default</code>-Datei anders aussieht, einfach den unteren Teil der <code>mod_jk_vhosts</code>-Datei mit dem Inhalt der <code>default</code>-Konfiguration abgleichen.</p>
<p>Zur Aktivierung der alternativen Konfiguration in der Konsole folgende Zeile ausführen:</p>
<pre class="brush: plain; gutter: false;">
sudo a2ensite mod_jk_vhosts
</pre>
<h3>jk.conf</h3>
<p>Die zweite Datei der ich mich widmen will, ist die <code>jk.conf</code>. Wie bereits erwähnt: sollte diese Datei noch nicht existieren, einfach unter dem oben genannten Pfad mit folgendem Inhalt speichern.</p>
<pre class="brush: plain;">
JkWorkersFile /etc/apache2/workers.properties
JkLogFile /var/log/apache2/mod_jk.log
JkLogLevel info
</pre>
<p>Die Konfiguration ist sehr minimalistisch. Mehr wird auch erstmal nicht benötigt. Es wird nur die Stelle für die Konfigurationsdatei angegeben, die Apache braucht um mit dem Tomcat zu sprechen und die Logging-Konfiguration, für den Fall, dass etwas schief läuft.<br />
Damit diese Konfiguration auch berücksichtigt wird muss sie mit
<pre class="brush: plain; gutter: false;">sudo ln -s /etc/apache2/mods-available/jk.conf /etc/apache2/mods-enabled/</pre>
<p> verlinkt werden.</p>
<h3>workers.properties</h3>
<p>Die <code>workers.properties</code> kann man als das Herzstück der Konfiguration bezeichnen, da sie die eigentliche Kommunikation zwischen Apache und Tomcat ermöglicht.</p>
<pre class="brush: plain;">
workers.tomcat_home=/usr/share/tomcat6
workers.java_home=/usr/lib/jvm/java-6-sun
ps=/
worker.list=worker1
worker.worker1.port=8009
worker.worker1.host=localhost
worker.worker1.type=ajp13
worker.worker1.lbfactor=1
</pre>
<p>Der Kürze halber will ich an dieser Stelle nicht die einzelnen Parameter erklären, sondern nur auf die <a href="http://tomcat.apache.org/connectors-doc/reference/workers.html">offizielle Dokumentation</a> verweisen.</p>
<h3>server.xml</h3>
<p>Als dritte Datei kommen wir zur <code>/etc/tomcat6/server.xml</code>. Diese enthält die allgemeine Server-Konfiguration für den integrierten Tomcat von Ubuntu. An dieser Datei müssen zwei Änderungen durchgeführt werden:</p>
<ol>
<li>Aktivierung von Port 8009 und</li>
<li>Server-Aliase für unseren VirtualHost setzen.</li>
</ol>
<p>Für 1. einfach nach <code>port="8009"</code> suchen und die Zeile auskommentieren, sodass es in etwa so aussieht</p>
<pre class="brush: plain;">
...
&lt;!-- Define an AJP 1.3 Connector on port 8009 --&gt;
&lt;Connector port=&quot;8009&quot; protocol=&quot;AJP/1.3&quot; redirectPort=&quot;8443&quot; /&gt;
...
</pre>
<p>Die Server-Aliase werden im Abschnitt <code>Host</code> eingetragen.</p>
<pre class="brush: plain;">
...
&lt;Host name=&quot;localhost&quot; appBase=&quot;webapps&quot; unpackWARs=&quot;true&quot; autoDeploy=&quot;true&quot; xmlValidation=&quot;false&quot; xmlNamespaceAware=&quot;false&quot;&gt;
  ...
  &lt;Alias&gt;www.tomcat.localhost&lt;/Alias&gt;
  &lt;Alias&gt;tomcat.localhost&lt;/Alias&gt;
  &lt;Alias&gt;127.0.0.2&lt;/Alias&gt;
  &lt;Alias&gt;tomcat.localhost&lt;/Alias&gt;
&lt;/Host&gt;
...
</pre>
<h3><code>/etc/hosts</code></h3>
<p>Als letzten Schritt soll auch Ubuntu erfahren zu welchem Servernamen welche IP gehört. Darum in die <code>/etc/hosts</code> folgende Zeilen hinzufügen:</p>
<pre class="brush: plain;">
127.0.0.2 tomcat.localhost www.tomcat.localhost
127.0.0.3 apache.localhost www.apache.localhost
</pre>
<h2>Das &#8220;Dessert&#8221;</h2>
<p>Auf das Dessert freut man sich ja eigentlich am meisten. So auch hier. Nachdem alles konfiguriert wurde, einfach den Tomcat und den Apache neustarten:</p>
<pre class="brush: plain; gutter: false;">
sudo /etc/init.d/tomcat6 restart
sudo /etc/init.d/apache2 restart
</pre>
<p>Violá, wir sind finis &#8230; zumindest was meinen Versuchsaufbau angeht. Falls noch alles läuft, habe ich was falsch gemacht. Im Ernst: Falls Kommentare sind, weil etwas nicht funktioniert bitte ich um User-generierten Content <img src='http://www.pincservices.de/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.pincservices.de/wordpress/recipe-apache-2-mit-tomcat-6-auf-ubuntu-9-10-fur-gourmets/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

