<?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>blogzwei</title>
	<atom:link href="http://www.wortzwei.de/blogzwei/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.wortzwei.de/blogzwei</link>
	<description>der Blog von Wortzwei</description>
	<lastBuildDate>Wed, 25 Jan 2012 14:33:01 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>KEENON FASHION ist live &#8211; und wir sind dabei!</title>
		<link>http://www.wortzwei.de/blogzwei/2012/01/keenon-fashion-ist-live-und-wir-sind-dabei/</link>
		<comments>http://www.wortzwei.de/blogzwei/2012/01/keenon-fashion-ist-live-und-wir-sind-dabei/#comments</comments>
		<pubDate>Wed, 25 Jan 2012 14:33:01 +0000</pubDate>
		<dc:creator>joris</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Softwareentwicklung]]></category>

		<guid isPermaLink="false">http://www.wortzwei.de/blogzwei/?p=966</guid>
		<description><![CDATA[Vermutlich herrschte schon allenthalben das Gefühl, wir von der wortzwei GmbH würden unser Blog still und leise zu Grabe tragen &#8211; dem ist aber nicht so! Wir hatten einfach nur unglaublich viel zu tun! Um so mehr freuen wir uns nun etwas großes, großartiges und neues vorzustellen: KEENON FASHION ist live! Wir haben für die [...]]]></description>
			<content:encoded><![CDATA[<p>Vermutlich herrschte schon allenthalben das Gefühl, wir von der wortzwei GmbH würden unser Blog still und leise zu Grabe tragen &#8211; dem ist aber nicht so! Wir hatten einfach nur unglaublich viel zu tun!<br />
<span id="more-966"></span><br />
Um so mehr freuen wir uns nun etwas großes, großartiges und neues vorzustellen: KEENON FASHION ist live! </p>
<p>Wir haben für die Otto-Tochter <a href="https://www.hermesworld.com/int/about_us/hermes_group/otto_international_gmbh/otto-international-gmbh.html">Hermes-OTTO International</a> die B2B-Handelsplattform KEENON FASHION umgesetzt und waren hierzu auch beratend tätig.</p>
<p>Mehr in der aktuellen Ausgabe der TextilWirtschaft und online <a href="http://etailment.de/2012/otto_b-to-b-plattform/">hier</a>.</p>
<p>Die Umsetzung erfolgte mittels Java &amp; Grails.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.wortzwei.de/blogzwei/2012/01/keenon-fashion-ist-live-und-wir-sind-dabei/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Etwas Hype gefällig? &#8211; node.js und now</title>
		<link>http://www.wortzwei.de/blogzwei/2011/11/etwas-hype-gefallig-node-js-und-now/</link>
		<comments>http://www.wortzwei.de/blogzwei/2011/11/etwas-hype-gefallig-node-js-und-now/#comments</comments>
		<pubDate>Thu, 24 Nov 2011 11:19:11 +0000</pubDate>
		<dc:creator>alex</dc:creator>
				<category><![CDATA[Allgemein]]></category>

		<guid isPermaLink="false">http://www.wortzwei.de/blogzwei/?p=911</guid>
		<description><![CDATA[Wenn man sich momentan in der Web-Entwickler-Gemeinde umhört, kommt man nicht drum rum, als sich mit dem Begriff node.js &#8220;bewerfen&#8221; zu lassen. Wie bei vielen Hypes, sollte man hinterfragen, ob es sich bei node.js wirklich um eine praxistaugliche Innovation handelt oder ein BWLer-Buzzword, dass möglichst häufig und an den unsinnigsten Stellen eingeworfen wird, nur um [...]]]></description>
			<content:encoded><![CDATA[<p>Wenn man sich momentan in der Web-Entwickler-Gemeinde umhört, kommt man nicht drum rum, als sich mit dem Begriff <strong>node.js</strong> &#8220;bewerfen&#8221; zu lassen.</p>
<p>Wie bei vielen Hypes, sollte man hinterfragen, ob es sich bei node.js wirklich um eine praxistaugliche Innovation handelt oder ein BWLer-Buzzword, dass möglichst häufig und an den unsinnigsten Stellen eingeworfen wird, nur um es einmal gesagt zu haben. Denn nur, wenn einem eine Technologie wirklich einen Mehrwert bringt, lohnt es sich, sie in den Firmenalltag zu integrieren und auch vor Kunden zu vertreten.<span id="more-911"></span></p>
<p>Ich gehe davon aus, dass die Leser dieses Blogs schon eine ungefähre &#8220;Ahnung&#8221; haben, wobei es sich bei node.js handelt, wenn nicht <a class="wp-oembed" title="node.js" href="http://de.wikipedia.org/wiki/Node.js" target="_blank">http://de.wikipedia.org/wiki/Node.js</a></p>
<p>Um es kurz zusammenzufassen, handelt es sich bei node.js um eine Technologie, mit der man serverseitig JavaScript-Code ausführen kann. Das klingt für den eingefleischten Perl/PHP/Ruby-Entwickler zunächst sicher etwas &#8220;widernatürlich&#8221;. Aber wie bei vielen neuen Dingen, hat man ersteinmal etwas dagegen, weil man es nicht kennt, obwohl es vielleicht gar nicht so abwegig ist, wie es zunächst den Anschein hat.</p>
<p>So muss man gestehen, dass node.js mit der V8-Google-Engine in Performance, durch JIT-Kompilierung, InLine-Cache und neuer Speicherverwaltung, nahe an vorkompilierte Sprachen wie C oder C++ heranreicht.</p>
<p>Doch was genau für Vorteile hat das nun für uns, als &#8220;Nicht-C++&#8221;-Programmierer, dass jemand aus einem Geistesblitz heraus eine JavaScript-Engine auf dem Server einsetzt? Da gibt es doch schon mehr als genug andere ScriptSprachen, wie PHP, Perl, etc. Warum da das Rad neu erfinden?</p>
<p>Zuersteinmal bietet <strong>node</strong> die Möglichkeit einen eigenen Web-Server zu &#8220;bauen&#8221;, der entgegen den üblichen Web-Servern nicht auf &#8220;Ein Thread pro Request&#8221; setzt, sondern auf einen Thread für die Verarbeitung <strong>aller</strong> Requests, aber auf eine eventbasierte <strong>non-blocking-I/O</strong>.</p>
<p>ACHSO!&#8230;&#8230;&#8230;Was?!</p>
<p>Nun, in einem Apache-MySql-PHP-Setup würde ein Request einen eigenen Thread starten, einen für sich isolierten &#8220;Bereich&#8221;, wenn man so will. Eben hierdrin würde dann der PHP-Interpreter seine Arbeit aufnehmen und den Request beantworten. Kommt zur gleichen Zeit noch ein Request, passiert das Gleiche nocheinmal&#8230;in einem neuen Thread und dann wieder und wieder und wieder&#8230;.</p>
<p>Man versucht also den Thread so schnell wie möglich abzuarbeiten, um ihn wieder &#8220;frei&#8221; zu machen, denn jeder Server kann nur eine begrenzte Menge an Threads &#8220;poolen&#8221; bevor er nicht mehr reagieren kann, da seine Resourcen aufgebraucht sind, bis die Threads abgearbeitet sind.</p>
<p>Jeder der einmal ein High-Performance-Speedtestingtool auf seine Seiten losgelassen hat, das unzählige Anfragen in einer Sekunde generieren kann, weiß wovon ich rede.</p>
<p>Das Problem ist aber nicht alleine die begrenzte Verfügbarkeit von Threads, sondern auch, dass Threads nur dann schnell abgearbeitet werden können, wenn kaum/keine Festplatten oder Datenbankoperationen stattfinden.</p>
<p>Denn das ist genau DAS was im Requesthandling am längsten dauert:</p>
<ul>
<li>Datenbankabfragen</li>
<li>Dateiuploads von großen Dateien</li>
<li>Verarbeitung von Dateien</li>
<li>Speichern von großen Mengen an User-Daten</li>
<li>API-Backendkommunikation</li>
</ul>
<p>Ein Webserver verbringt die meiste Zeit mit <strong>warten</strong>, das klingt vielleicht etwas seltsam ist aber so. Denn bevor die Datenbank den wichtigen Datensatz zurückgeliefert hat, der WebService nicht gemeldet hat, dass User X Bonität Y hat oder der Upload der großen CSV-Datei fertig ist, kann der Server den Request nicht beantworten und so den Thread wieder freigeben.</p>
<p>Und genau <strong>hier</strong> liegt die Stärke eines non-blocking-I/O mit Eventloop.</p>
<p>Eine Eventloop springt sehr schnell zwischen den Anfragen hin und her, startet die jeweilige I/O und setzt einen Callback für das Event der Fertigstellung (nur als grobes Beispiel). So kann der nächste Request bearbeitet werden, obwohl noch gar keine Antwort von der I/O-Aktion zurückgekommen ist. Sobald das &#8220;I/O-End-Event&#8221; auftritt, wird der Callback aufgerufen und der jeweilige Request kann zuende bearbeitet werden.</p>
<blockquote><p>Callbacks sind in node.js anonyme oder auch benamte Funktionen, die bestimmte Parameter erhalten. Meist einen Error-Parameter, einen Data-Parameter und noch diverse andere verschiedene Informationen und Objekte. Oft auch selbst wieder Funktionen als Paramter.</p></blockquote>
<p>Node.js ist also in der Lage das &#8220;C10K&#8221;-Problem zu lösen, also die Fähigkeit mehr als 10.000 Clients gleichzeitig zu &#8220;bedienen&#8221;. Zwar würde ein Apache unter Linux 2.6 Kernel das auch schaffen, da hier die Threadzahl bis 32.000 gehen kann, aber dazu muss man den Overhead der Threads schon sehr stark begrenzen, wenn man nicht auf einer 64 Bit Maschine unterwegs ist, sonst kommt man nicht annähernd an diese Zahl.<br />
<br class="clear" />Doch auch all diese Vorzüge sollen nicht darüber hinwegtäuschen, dass node.js nicht für jeden Nagel der geeignete Hammer ist. <br class="clear" /><br class="clear" /><strong>Gute Einsatzgebiete:</strong></p>
<ul>
<li>Json-Webservices, hier ist node.js wirklich ein ganz Großer</li>
<li>Performance mittelgroßer Webseiten mit geringer Hardware-Anforderung</li>
<li>Single-Site-Applicationen, wie zb GoogleMail, sprich Anwendungen die über &#8220;AJAX&#8221; die Anwendungsoberfläche immer wieder erweitern und verändern</li>
</ul>
<p><strong>Schlechte Einsatzgebiete:</strong></p>
<ul>
<li>Webseiten mit hohem Anteil an Layoutvariationen und Templatefunktionalität, hier sind PHP, Ruby etc besser geeignet.</li>
<li>Hochverfügbarkeits-Systeme oder sehr kritische Produktionssysteme, dieses da sich node.js noch im frühen Entwicklungsstadium befindet. Der letzte stable Release ist 0.6.2 aus dem November 2011.</li>
</ul>
<p><br class="clear" /><br class="clear" /><br class="clear" /><br class="clear" /></p>
<h3><strong>NOW</strong></h3>
<p>Was node.js aber instressant machen könnte, ist das <strong>NOW-Framework</strong> für node.js, welches die Möglichkeit bietet, serverseitigen Code im Browser zu nutzen und Client-Funktionen vom Server aus aufzurufen.</p>
<p>Das muss man erstmal sacken lassen, man könnte also vom Server aus eine clientseitige JavaScript-Funktion aufrufen? JA! Man kann&#8230;</p>
<p>Und das alles ohne wirkliches AJAX! Über eine Socket-I/O-Funktionalität aus dem NOW-Framework für node.js. Dieses Framework macht es einem möglich über den NOW-Namespace Funktionen über Netzwerk Client- Und Serverseitig zu teilen.</p>
<p>Es ist auch möglich serverseitig Variablen zu setzen und sie zeitgleich im Client zu nutzen. In Real-Time!</p>
<p>So ist es zum Bespiel möglich mit nur 12 Zeilen Code einen einfachen Chatclient zu schreiben!</p>
<p>Hier ein Beispiel:</p>
<h3><strong>Serverseitig:</strong></h3>
<pre>var fs = require('fs');
var http = require('http');

var server = http.createServer(function(req,res){

    fs.readFile('index.html', function(err,data){

       res.writeHead(200,{'Content-Type' : 'text/html'});
       res.write(data);
       res.end();
    });

}).listen(8080);

var everyone = require("now").initialize(server);

everyone.now.distributeMessage = function(msg){
  everyone.now.receiveMessage(this.now.name, msg);
};</pre>
<h3><strong>Clientseitig:</strong></h3>
<pre>$(document).ready(function(){
                now.name = prompt("Wie ist dein Name?","");
                now.receiveMessage = function(name,msg){
                      $("&lt;div&gt;&lt;/div&gt;").text(name + ": "+msg).appendTo('#msg');
                };

                $("#send-button").click(function(){
                   now.distributeMessage($('#text-input').val());
                   $('#text-input').val("");
                });
            });</pre>
<p><br class="clear" /></p>
<p><strong> Wenn das alles etwas neugierig gemacht hat, der kann gerne hier nachlesen:</strong></p>
<ul>
<li><a href="http://nodejs.org/" target="_BLANK">nodejs.org</a></li>
<li><a href="http://nowjs.com/" target="_BLANK">nowjs.com</a></li>
</ul>
<p><br class="clear" /><br class="clear" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.wortzwei.de/blogzwei/2011/11/etwas-hype-gefallig-node-js-und-now/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java als Service unter Windows</title>
		<link>http://www.wortzwei.de/blogzwei/2011/11/java-als-service-unter-windows/</link>
		<comments>http://www.wortzwei.de/blogzwei/2011/11/java-als-service-unter-windows/#comments</comments>
		<pubDate>Fri, 04 Nov 2011 12:49:57 +0000</pubDate>
		<dc:creator>dirk</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Linux/Unix]]></category>
		<category><![CDATA[Softwareentwicklung]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[procrun]]></category>
		<category><![CDATA[prunsrv]]></category>
		<category><![CDATA[service]]></category>
		<category><![CDATA[srvany]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.wortzwei.de/blogzwei/?p=878</guid>
		<description><![CDATA[Um ein Java-Programm als Service unter Windows zu betreiben benötigt man einen Service-Wrapper (da führt kein Weg dran vorbei). Unter Linux gibt es auch Service-Wrapper aber dort kann man Java auch direkt als Daemon ausführen. Unter Linux habe ich mir bis jetzt immer ein passendes init.d Script runtergeladen und das leicht angepasst. Linux ist da [...]]]></description>
			<content:encoded><![CDATA[<p>Um ein Java-Programm als Service unter Windows zu betreiben benötigt man einen Service-Wrapper (da führt kein Weg dran vorbei). Unter Linux gibt es auch Service-Wrapper aber dort kann man Java auch direkt als Daemon ausführen. Unter Linux habe ich mir bis jetzt immer ein passendes <code>init.d</code> Script runtergeladen und das leicht angepasst. Linux ist da eben (wie immer) einen Schritt weiter. Aber manchmal kommt man eben nicht daran vorbei einen Service unter Windows laufen zu lassen. <i>*seufz*</i> <span id="more-878"></span></p>
<p>Für Windows hab ich auf die schnelle zwei Wrapper gefunden:</p>
<ul>
<li>srvany (von Microsoft)</li>
<li><a href="http://commons.apache.org/daemon/procrun.html">Procrun (von Apache)</a></li>
</ul>
<p>Da <i>Procrun</i> von Apache ist und wohl auch vom Tomcat verwendet wird habe ich mich entschlossen das Tool zu nutzen.</p>
<p><i>Procrun</i> besteht aus zwei Programmen:</p>
<ol>
<li>Prunmgr (Procrun monitor application) ist eine GUI um <i>Procrun</i> Dienste zu konfigurieren.</li>
<li>Prunsrv (Procrun service application) ist der eigentliche Service-Wrapper</li>
</ol>
<p>Die Monitor-Applikation ist nicht so interessant deshalb betrachten wir hier nur den Wrapper. Der Wrapper kann in drei Modes laufen:</p>
<ol>
<li>Im Mode <code>jvm</code> wird direkt die <code>jvm.dll</code> verwendet um das Java-Programm zum Service zu machen. Das gewünschte Java-Programm läuft so in dem Prozess des Wrappers.</li>
<li>Im Mode <code>exe</code> kann eine beliebige anderes (native) Programm als Service gestartet werden. Das Programm wird dabei in einem eigenen Prozess gestartet.</li>
<li>Der Mode <code>java</code> ähnelt sehr dem Mode <code>exe</code> nur das hier automatisch die <code>java.exe</code> in einem eigenen Prozess gestartet wird.</li>
</ol>
<p>Ich finde eigentlich den Mode <code>jvm</code> am besten. Die Idee das Java-Programm in dem Prozess laufen zu lassen finde ich eigentlich recht charmant und die Implementierung kann man leicht so gestalten das mein <code>init.d</code> Ansatz für Linux mit dem gleichen Source-Code funktioniert.</p>
<p>Um unser Beispiel-Programm als Service zu installieren lädt man sich die Binaries von der Apache-Seite herunter. Dann braucht ihr natürlich auch meine <a href='http://www.wortzwei.de/blogzwei/wp-content/uploads/2011/11/SimpleService.zip'>Sample-App</a> (ist Eclipse-Projekt). Dann entpackt ihr das Sampel und entpackt die Distribution von Apache so das die <code>prunsrv</code> in dem Verzeichnis liegt in das ihr mein Beispiel entpackt habt. Dann könnt ihr mit dem Batch-Script (<code>service_install.bat</code>) den Service installieren:</p>
<pre>
@ECHO OFF
%~dp0\prunsrv //IS//SimpleService  ^
	--Jvm=auto --StartMode=jvm --StopMode=jvm  ^
	--Classpath %~dp0\SimpleService.jar  ^
	--StartClass de.wortzwei.simpleService.Service --StartParams start  ^
	--StopClass de.wortzwei.simpleService.Service --StopParams stop  ^
	--StartPath %~dp0 --LogPath %~dp0
</pre>
<p>Der Inhalt ist leicht erklärt (genauer könnt ihr das in der Dokumentation nachlesen): Es wird ein Service mit dem Namen &#8220;SimpleService&#8221; installiert. Die Jvm wird automatisch bestimmt und das Starten bzw. Stoppen passiert im Modus <code>jvm</code>. Natürlich muss der <code>Classpath</code>, das Working-Directory (<code>StartPath</code>) und der <code>LogPath</code> (hier schreibt das Tool sein eigenes Log) gesetzt werden. Das Working-Directory ist deshalb so wichtig da unser Service dort seine Einstellungen sucht. Dieses seltsame <code>%~dp0</code> wird übrigens zum Verzeichnis erweitert in dem sich diese Bat-Datei befindet. Wirklich wichtig sind die Einstellungen <code>StartClass</code>, <code>StopClass</code>, <code>StartParams</code> und <code>StopParams</code> denn hier wird eingestellt das die Methode <code>main</code> (ist der default und kann auch noch eingestellt werden) in der Klasse <code>de.wortzwei.simpleService.Service</code> mit dem Parameter <code>start</code> zum starten bzw. <code>stop</code> zum stoppen aufgerufen wird. Die Main-Methode wird dabei nicht zum starten der VM aufgerufen sondern wird wie eine normale statische Methode aufgerufen.</p>
<p>Sehen wir uns die Main-Methode an:</p>
<pre>
public static void main(final String[] args) {
	// default ist "start"
	String cmd = CMD_START;
	if (args.length &gt; 0) {
		cmd = args[0];
	}

	if (cmd.equalsIgnoreCase(CMD_START)) {
		Thread.setDefaultUncaughtExceptionHandler(new ExtUncaughtExceptionHandler());
		try {
			final Settings settings = new Settings();
			// den Server starten
			server = new Server(settings.getPort(),
			        settings.getMaxRequests(), new FileFactory(
			                settings.getOutput()));
			server.start();
		} catch (final IOException e) {
			System.out.println("fatal error!");
			e.printStackTrace();
			System.exit(-1);
		}
	} else {
		if (server != null) {
			server.shutdown();
			try {
				server.join();
			} catch (final InterruptedException e) {
				System.out.println("Interrupted?");
				e.printStackTrace();
			}
		}
	}
}
</pre>
<p>Wie man sieht wird der <code>Server</code> (ein Thread) gestartet wenn &#8220;start&#8221; als erster Parameter übergeben wird. Jeder andere String wird als &#8220;stop&#8221; interpretiert. Hier ist es wichtig beim stoppen <b>nicht</b> <code>System.exit()</code> aufzurufen. Das würde ja die JVM abbrechen, die wir nicht selber gestartet haben (da wir hier in der <code>main</code> Methode sind täuscht das ein wenig) und unter Windows werden dann wirre Meldungen angezeigt von wegen der Service konnte nicht gestoppt werden. Im Prinzip macht der Service-Wrapper nichts anderes als dieses kleine Programm:</p>
<pre>
/**
 * Diese Methode startet den Service; wartet ein bisschen und stoppt ihn dann
 * wieder. Ähnlich wie der Service-Wrapper das macht.
 */
private static void startStopService() {
	// starten
	Service.main(new String[] { "start" });

	// warten
	try {
		Thread.sleep(1000);
	} catch (final InterruptedException e) {
		System.out.println("Interrupted?");
		e.printStackTrace();
	}

	// stoppen
	Service.main(new String[] { "stop" });
}
</pre>
<p>Wie bereits erwähnt ist das beste an diesem Ansatz das ich diese Main-Methode fast ohne Änderung so unter Linux auch verwenden kann. Unter Linux ruft das <code>init.d</code> Script zum stoppen des Daemons nur <code>kill -15 &lt;pid&gt;</code> auf (SIGTERM). Wenn man jetzt einen Shutdown-Hook registriert kann dieser das stoppen des Server-Threads übernehmen und mit ein bisschen Refactoring kann der Code der jetzt im Else-Zweig steht sogar von beiden Ansätzen verwendet werden.</p>
<p>problem soved! bis denn&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.wortzwei.de/blogzwei/2011/11/java-als-service-unter-windows/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Locale in einem Grails-Controller erzwingen</title>
		<link>http://www.wortzwei.de/blogzwei/2011/09/locale-in-einem-grails-controller-erzwingen/</link>
		<comments>http://www.wortzwei.de/blogzwei/2011/09/locale-in-einem-grails-controller-erzwingen/#comments</comments>
		<pubDate>Tue, 27 Sep 2011 12:12:46 +0000</pubDate>
		<dc:creator>Martin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Softwareentwicklung]]></category>
		<category><![CDATA[Action]]></category>
		<category><![CDATA[Controller]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[Locale]]></category>

		<guid isPermaLink="false">http://www.wortzwei.de/blogzwei/?p=867</guid>
		<description><![CDATA[Manchmal kann es nötig sein ein bestimmtes Locale zu erzwingen, dazu genügt es im betroffenen Controller das localeResolver-Bean injecten zu lassen und dann in einer Action oder im beforeInterceptor, wenn das erzwungene Locale für alle Actions gelten soll, per localeResolver.setLocale(...) das gewünschte Locale zu setzen. class LocaleEnforcingController { def localeResolver ... def beforeInterceptor = { [...]]]></description>
			<content:encoded><![CDATA[<p>Manchmal kann es nötig sein ein bestimmtes Locale zu erzwingen, dazu genügt es im betroffenen Controller das <code>localeResolver</code>-Bean injecten zu lassen und dann in einer Action oder im <code>beforeInterceptor</code>, wenn das erzwungene Locale für alle Actions gelten soll, per <code>localeResolver.setLocale(...)</code> das gewünschte Locale zu setzen.</p>
<p><span id="more-867"></span></p>
<pre>
class LocaleEnforcingController {

  def localeResolver

  ...

  def beforeInterceptor = {
    localeResolver.setLocale(request, response, new Locale(...))
  }

  ...

  def someAction = {
    ...
    localeResolver.setLocale(request, response, new Locale(...))
    ...
  }

}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.wortzwei.de/blogzwei/2011/09/locale-in-einem-grails-controller-erzwingen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Groovy Meta-Programming mit der ExpandoMetaClass</title>
		<link>http://www.wortzwei.de/blogzwei/2011/04/groovy-meta-programming-mit-der-expandometaclass/</link>
		<comments>http://www.wortzwei.de/blogzwei/2011/04/groovy-meta-programming-mit-der-expandometaclass/#comments</comments>
		<pubDate>Thu, 31 Mar 2011 22:07:52 +0000</pubDate>
		<dc:creator>dirk</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Softwareentwicklung]]></category>

		<guid isPermaLink="false">http://www.wortzwei.de/blogzwei/?p=858</guid>
		<description><![CDATA[Ich bin gerade dabei Groovy zu lernen. Wenn ich etwas komplett neues lerne gehe ich eigentlich immer so vor: Im Internet soviel Dokumentation lesen wie verfügbar ist. Ein gutes Buch kaufen und komplett lesen. machen&#8230; Bei Groovy bin ich gerade beim &#8220;machen&#8221; angekommen . Besonders cool finde ich die Unterstützung für Meta-Programming. Nur die Suche [...]]]></description>
			<content:encoded><![CDATA[<p>Ich bin gerade dabei Groovy zu lernen. Wenn ich etwas komplett neues lerne gehe ich eigentlich immer so vor:</p>
<ol>
<li>Im Internet soviel Dokumentation lesen wie verfügbar ist.</li>
<li>Ein gutes Buch kaufen und komplett lesen.</li>
<li>machen&#8230;</li>
</ol>
<p>Bei Groovy bin ich gerade beim &#8220;machen&#8221; angekommen <img src='http://www.wortzwei.de/blogzwei/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .<br />
<span id="more-858"></span></p>
<p>Besonders cool finde ich die Unterstützung für Meta-Programming. Nur die Suche nach einem sinnvollen Beispiel gestaltete sich etwas schwierig. Groovy hat die grundlegenden Klassen von Java bereits mit genügend sehr nützlichen Funktionen ausgestattet. Mir ist allerdings aufgefallen das in String keine Funktion wie <a href="http://commons.apache.org/lang/api-2.5/org/apache/commons/lang/StringUtils.html#isBlank(java.lang.String)">StringUtils.isBlank()</a> hinzugefügt wurde. Die Funktion gehört zu meinen Lieblingsfunktionen und ich verwende sie sehr oft.</p>
<p>Dank der ExpandoMetaClass lässt sich die Funktion leicht hinzufügen:</p>
<pre>
void testIsBlank() {
    String.metaClass.isBlank = {
        -&gt;
        int strLen;
        if ((strLen = delegate.length()) == 0) {
            return true;
        }
        for (int i = 0; i &lt; strLen; i++) {
            if ((Character.isWhitespace(delegate.charAt(i)) == false)) {
                return false;
            }
        }
        return true;
    }

    assertTrue &#039; &#039;.blank
    assertTrue &#039;&#039;.blank
    assertFalse &#039;bob&#039;.blank
    assertFalse &#039; bob &#039;.blank
}
</pre>
<p>Vielleicht finden sich ja noch andere nützliche Funktionen in den StringUtils die man einfach String hinzufügen kann?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.wortzwei.de/blogzwei/2011/04/groovy-meta-programming-mit-der-expandometaclass/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Eigene Android ListView mit Selektionsdarstellung</title>
		<link>http://www.wortzwei.de/blogzwei/2011/03/eigene-android-listview-mit-selektionsdarstellung/</link>
		<comments>http://www.wortzwei.de/blogzwei/2011/03/eigene-android-listview-mit-selektionsdarstellung/#comments</comments>
		<pubDate>Tue, 08 Mar 2011 10:57:33 +0000</pubDate>
		<dc:creator>steve</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Softwareentwicklung]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[ListView]]></category>

		<guid isPermaLink="false">http://www.wortzwei.de/blogzwei/?p=834</guid>
		<description><![CDATA[In diesem Artikel möchte ich vorstellen, wie man eine Android ListView erstellt, die wie android.R.layout.simple_list_item_single_choice mit Radiobuttons anzeigt, welches Element gerade selektiert ist, allerdings mit einem eigenen Layout verfeinert wurde. Ziel ist es eine ListView zu implementieren, die wie folgt aussieht: Jeder Eintrag verfügt über ein Icon auf der linken Seite und ein RadioButton auf [...]]]></description>
			<content:encoded><![CDATA[<p>In diesem Artikel möchte ich vorstellen, wie man eine Android ListView erstellt, die wie <code>android.R.layout.simple_list_item_single_choice</code> mit Radiobuttons anzeigt, welches Element gerade selektiert ist, allerdings mit einem eigenen Layout verfeinert wurde.</p>
<p><span id="more-834"></span>Ziel ist es eine ListView zu implementieren, die wie folgt aussieht:</p>
<p><a href="http://www.wortzwei.de/blogzwei/wp-content/uploads/2011/03/listViewDemo1.png"><img class="aligncenter size-medium wp-image-844" src="http://www.wortzwei.de/blogzwei/wp-content/uploads/2011/03/listViewDemo1-197x300.png" alt="" width="197" height="300" /></a></p>
<p>Jeder Eintrag verfügt über ein Icon auf der linken Seite und ein RadioButton auf der rechten Seite, welches den selektierten Eintrag anzeigt. Das Layout für die Aktivität <code>list_view_demo.xml</code>:</p>
<pre>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent"&gt;

&lt;RelativeLayout android:layout_width="fill_parent"
android:orientation="horizontal" android:layout_height="wrap_content"
android:paddingTop="10dp" style="@android:style/ButtonBar"&gt;

&lt;Button android:id="@+id/choose_btn" android:text="@string/choose_btn"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:enabled="true" android:layout_alignParentRight="true" /&gt;

&lt;/RelativeLayout&gt;

&lt;ListView android:id="@+id/list_view" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:drawSelectorOnTop="false" /&gt;

&lt;/LinearLayout&gt;</pre>
<p>und speziell für jeden Listeneintrag soll das Layout <code>list_entry.xml</code> genutzt werden. Hier gilt es zu beachten, dass nicht eine <code>CheckBox</code> sondern eine <code>CheckedTextView</code> genutzt wird. Damit wird der Touch-Event immer von der Liste verarbeitet.</p>
<pre>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="64dip"
android:gravity="center_vertical" android:ignoreGravity="@+id/icon"&gt;

&lt;ImageView android:id="@+id/icon"
android:layout_alignParentLeft="true" android:layout_alignParentTop="true"
android:layout_alignParentBottom="true" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:src="@drawable/icon" /&gt;

&lt;TextView android:id="@+id/label"
android:layout_width="200dp" android:paddingLeft="9dip"
android:layout_height="wrap_content" android:layout_toRightOf="@id/icon"
android:layout_centerVertical="true" android:textSize="23dp" /&gt;

&lt;CheckedTextView android:id="@+id/checkstate"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_marginRight="6dip" android:layout_alignParentRight="true"
android:background="#00000000" android:focusable="false"
android:clickable="false" android:checked="false"
android:checkMark="@android:drawable/btn_radio"
android:layout_centerVertical="true"
/&gt;

&lt;/RelativeLayout&gt;</pre>
<p>Damit ist das Layout definiert und muss nur noch an die Liste übergeben werden. Dies erfolgt durch die Implementierung eines eigenen Adapters. Hierzu habe ich eine private Klasse <code>DomainExampleAdapter</code> erstellt, die mit dem DomainObject <code>DomainExample</code> zusammenarbeitet.</p>
<pre>private class DomainExampleAdapter extends ArrayAdapter&lt;DomainExample&gt; {

  DomainExampleAdapter() {
    super(getApplicationContext(), R.layout.list_entry, itemList);
  }

  public View getView(int position, View convertView, ViewGroup parent) {
    View row = convertView;

    if (row == null) {
      LayoutInflater inflater = getLayoutInflater();
      row = inflater.inflate(R.layout.list_entry, parent, false);
    }

    TextView label = (TextView) row.findViewById(R.id.label);
    CheckedTextView checkBox = (CheckedTextView) row.findViewById(R.id.checkstate);

    label.setText(itemList.get(position).toString());
    checkBox.setChecked(listView.getCheckedItemPosition() == position);
    return (row);
  }
}</pre>
<p>Das zuvor vorgestellte Layout wird im Konstruktor und Inflater explizit genutzt. Das Überschreiben der Methode <code>getView</code>, welches für jeden Listeneintrag aufgerufen wird, bewirkt, dass das Label und die Checkbox entsprechend gesetzt wird. Hier der Vollständigkeit halber die Klasse <code>DomainExample</code>:</p>
<pre>
public class DomainExample {

  private int id;

  private String name;

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String toString() {
    return getName();
  }
}
</pre>
<p>Die Initialisierung der Activity erfolgt wie folgt:</p>
<pre>public class ListViewDemo extends Activity implements View.OnClickListener {

  private ListView listView = null;
  List&lt;DomainExample&gt; itemList = null;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.list_view_demo);

    itemList = getItemList();
    listView = (ListView) findViewById(R.id.list_view);
    listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
    listView.setAdapter(new DomainExampleAdapter());
    ...
}
...
}</pre>
<p>Die Liste mit den Einträgen wird durch die private Method <code>getItemList</code>. Erzeugt. Anschließend wird die listView anhand der Id ermittelt und der ChoiceMode auf <code>single</code> gesetzt. Dies ist besonders wichtig, da die selektierte Zeile ansonsten nicht über die Methode <code>getCheckedItemPosition()</code> abgefragt werden kann. Zu guter letzt wird der eigene Adapter an die ListView gehängt. Damit haben wir die oben prästentierte ListView komplett umgesetzt.</p>
<p>Ein vollständiges implementiertes Beispiel kann <a href='http://www.wortzwei.de/blogzwei/wp-content/uploads/2011/03/ListViewDemo.zip'>hier</a> heruntergeladen werden. Viel Spaß damit!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.wortzwei.de/blogzwei/2011/03/eigene-android-listview-mit-selektionsdarstellung/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>div-Element mit float-Content</title>
		<link>http://www.wortzwei.de/blogzwei/2011/02/div-element-mit-float-content/</link>
		<comments>http://www.wortzwei.de/blogzwei/2011/02/div-element-mit-float-content/#comments</comments>
		<pubDate>Mon, 21 Feb 2011 11:10:56 +0000</pubDate>
		<dc:creator>sven</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>

		<guid isPermaLink="false">http://www.wortzwei.de/blogzwei/?p=461</guid>
		<description><![CDATA[Häufig wünscht sich der gewiefte Webentwickler einen div-Container, in dem diverse Elemente herum-floaten. Der Wunsch nach einer automatischen Höhenanpassung des umschließenden div führt gerne zu einem zusätzlichem Subelement, welches mit style="clear:both" das floating beendet und somit die umschließende Höhenberechnung anstößt. Doch es gibt da auch einen anderen Weg, denn dieses Problem ist komplett mit CSS [...]]]></description>
			<content:encoded><![CDATA[<p>Häufig wünscht sich der gewiefte Webentwickler einen <code>div</code>-Container, in dem diverse Elemente herum-floaten. Der Wunsch nach einer automatischen Höhenanpassung des umschließenden <code>div</code> führt gerne zu einem zusätzlichem Subelement, welches mit <code>style="clear:both"</code> das floating beendet und somit die umschließende Höhenberechnung anstößt. Doch es gibt da auch einen anderen Weg, denn dieses Problem ist komplett mit CSS und ohne ein solch semantisch sinnbefreites Element lösbar!</p>
<p><span id="more-461"></span></p>
<p><strong>Zunächst das Ausgangsproblem:</strong></p>
<pre>&lt;div class="container"&gt;
	&lt;div class="element"&gt;Lorem ipsum ...&lt;/div&gt;
	&lt;div class="element"&gt;Lorem ipsum ...&lt;/div&gt;
&lt;/div&gt;</pre>
<pre>.container {
	margin: 10px;
	padding: 10px;
	background: red;
}
.element {
	margin: 5px; background: yellow;
	float: left;
}</pre>
<p>Aktuelle Situation:<br />
<img src="http://www.wortzwei.de/blogzwei/wp-content/uploads/2010/10/floating_problem.png" alt="floating_problem" width="280" height="70" class="size-full wp-image-473" /><br />
So soll es aussehen:<br />
<img src="http://www.wortzwei.de/blogzwei/wp-content/uploads/2010/10/floating_geloest.png" alt="floating_geloest" width="280" height="70" class="size-full wp-image-473" /></p>
<p><strong>Lösung mittels zusätzlichem Subelement:</strong><br />
Durch Anhängen eines Subelements (bspw. <code>br</code>) mit <code>style="clear:both"</code> wird das floating unterbrochen und die Containerhöhe korrekt berechnet.</p>
<pre>&lt;div class="container"&gt;
	...
	&lt;br style="clear:both" /&gt;
&lt;/div&gt;</pre>
<p><strong>Lösung mit CSS und nichts als CSS:</strong><br />
Fügt man dem Container-<code>div</code> lediglich die folgenden beiden CSS-Attribute zu, so kann man sich das Subelement sparen!</p>
<pre>.container {
	...
	overflow: hidden;	/* für den IE7 und drunter */
	display: table;		/* für den Rest der Browserwelt */
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.wortzwei.de/blogzwei/2011/02/div-element-mit-float-content/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bloom Filter</title>
		<link>http://www.wortzwei.de/blogzwei/2011/01/bloom-filter/</link>
		<comments>http://www.wortzwei.de/blogzwei/2011/01/bloom-filter/#comments</comments>
		<pubDate>Mon, 31 Jan 2011 09:54:49 +0000</pubDate>
		<dc:creator>Martin</dc:creator>
				<category><![CDATA[Softwareentwicklung]]></category>

		<guid isPermaLink="false">http://www.wortzwei.de/blogzwei/?p=816</guid>
		<description><![CDATA[Ein Bloom-Filter ist eine probabilistische Datenstruktur mit geringer Speicherkomplexität, die verwendet werden kann um zu prüfen, ob ein Element in einer Menge enthalten ist.]]></description>
			<content:encoded><![CDATA[<p>Ein Bloom-Filter ist eine probabilistische Datenstruktur mit geringer Speicherkomplexität, die verwendet werden kann um zu prüfen, ob ein Element in einer Menge enthalten ist. Der Test kann <em>false-positives</em> liefern, d.h. mit einer gewissen Wahrscheinlichkeit, die proportional zur Anzahl der in der Menge enthaltenen Elemente ist, wird ein Element fälschlicherweise als zur Menge zugehörig deklariert, es werden jedoch nie <em>false-negatives</em> geliefert.<span id="more-816"></span></p>
<h3>Funktionsweise</h3>
<p>Ein Bloom-Filter basiert grundlegend auf einem <strong><em>m</em></strong>-stelligen bit-Array, das initial mit Nullen  gefüllt ist und <strong><em>k</em></strong> Hashfunktionen, die die Elemente des Definitionsbereich auf die <strong><em>m</em></strong> Arrayindizes abbilden. Um ein Element zum Filter hinzuzufügen, wird das Element über die Hashfunktionen auf <strong><em>k</em></strong> Arrayindizes abgebildet und das bit-Array wird in jedem der berechneten Indizes auf <strong><em>1</em></strong> gesetzt. Um zu testen, ob ein Element im Filter enthalten ist werden ebenfalls über die Hashfunktion <strong><em>k</em></strong> Indizes berechnet, enthält das Array nun in einem der Indizes einen Wert ungleich <em><strong>1</strong></em> ist das Element nicht im Filter enthalten. Die Breite <em><strong>m</strong></em> des Arrays und die Anzahl <strong><em>k</em></strong> der Hashfunktionen bestimmt die Wahrscheinlichkeit von <em>false-positives</em>, je höher man diese wählt desto geringer diese Wahrscheinlichkeit.</p>
<p>Aus einem Bloom-Filter, der nach diesem einfachen Prinzip implementiert ist können keine Elemente entfernt werden, es gibt jedoch Lösungsansätze um dies zu ermöglichen.</p>
<h3>Anwendungsfälle</h3>
<p>Der Einsatz eines Bloom-Filters ist dann sinnvoll, wenn gegen eine große Menge an Daten getestet werden muss und false-positives zu vertreten sind. Beispielsweise der Ausschluss von Dubletten bei der Erzeugung von Gutscheincodes gegen einen bereits vorhandenen Datenbestand.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.wortzwei.de/blogzwei/2011/01/bloom-filter/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Vektorgrafiken mit Raphaël</title>
		<link>http://www.wortzwei.de/blogzwei/2011/01/vektorgrafiken-mit-raphael/</link>
		<comments>http://www.wortzwei.de/blogzwei/2011/01/vektorgrafiken-mit-raphael/#comments</comments>
		<pubDate>Fri, 28 Jan 2011 16:00:25 +0000</pubDate>
		<dc:creator>andreas</dc:creator>
				<category><![CDATA[Softwareentwicklung]]></category>
		<category><![CDATA[Labs]]></category>
		<category><![CDATA[Raphaël]]></category>
		<category><![CDATA[SVG]]></category>

		<guid isPermaLink="false">http://www.wortzwei.de/blogzwei/?p=778</guid>
		<description><![CDATA[Die Raphaël JavaScript Bibliothek ermöglicht es sehr komfortabel Vektorgrafiken mit JavaScript zu erstellen. Es bietet eine einfache API mit der man grafische Elemente erzeugen, manipulieren und animieren kann. Dabei wird je nach Browser SVG oder VML erzeugt. Als Entwickler muss man sich wegen der Browserkompatibilität keine Gedanken machen. Es werden die Browser Firefox 3.0+, Safari [...]]]></description>
			<content:encoded><![CDATA[<p>Die <a href="http://raphaeljs.com/">Raphaël</a> JavaScript Bibliothek ermöglicht es sehr komfortabel Vektorgrafiken mit JavaScript zu erstellen. Es bietet eine einfache API mit der man grafische Elemente erzeugen, manipulieren und animieren kann. Dabei wird je nach Browser SVG oder VML erzeugt. Als Entwickler muss man sich wegen der Browserkompatibilität keine Gedanken machen. Es werden die Browser Firefox 3.0+, Safari 3.0+, Chrome 5.0+, Opera 9.5+ und Internet Explorer 6.0+ unterstützt. Als Entwickler muss man vor allem auch kein Spezi für Vektorgrafiken sein, um mit der Raphaël JavaScript Bibliothek schnell ordentliche Ergebnisse zu erzielen. Ich werde anhand einiger Beispiele erläutern, wie man interaktive Elemente erstellen kann.<span id="more-778"></span></p>
<p>Zunächst möchte ich ein MovableRectangle Element erzeugen. Ein Rechteck das ich per Mouse hin und her schieben kann, und Basis für weitere Elemente sein wird. Dazu erstelle ich ein klassenähnliches JavaScript Konstrukt mit Feldern und Methoden, das ein primitives Rechteck (ein Raphaël Objekt vom Typ rect) kapselt.</p>
<pre>var MovableRectangle = function () {

    var _raphael = null;
    var _svgObj = null;
    var _instance = null;

    var _x = 0;
    var _y = 0;
    var _oldX = 0;
    var _oldY = 0;

    var _width = 0;
    var _height = 0;
    var _oldWidth = 0;
    var _oldHeight = 0;

    return {
        init: function (r, x, y, width, height, curve) {
            _raphael = r;
            _x = x;
            _y = y;
            _width = width;
            _height = height;
            _svgObj = _raphael.rect(_x, _y, _width, _height, curve);
            _instance = this;

            _svgObj.drag(this.move, this.start, this.up);

        },

        /* Getter und Setter für die alle Felder _x, _y, _width ...*/

        setAttr: function (key, value) {
            _svgObj.attr(key, value);
        },

        render: function () {
            _svgObj.attr('x', _x);
            _svgObj.attr('y', _y);
            _svgObj.attr('width', _width);
            _svgObj.attr('height', _height);
        },

        start: function (x, y) {
            _oldX = _x;
            _oldY = _y;
            _oldWidth = _width
            _oldHeight = _height;
            _instance.setAttr("opacity", 0.5);
        },

        move: function (deltaX, deltaY) {
            _x = _oldX + deltaX;
            _y = _oldY + deltaY;
            _instance.render();
        },

        up: function (event) {
            _instance.setAttr("opacity", 1);
        }
    }
}

var paper = Raphael('notepad', 640, 400);
var mr = new MovableRectangle();
mr.init(paper, 50, 50, 100, 100, 5);
mr.setAttr('fill', '#369');</pre>
<p>Was wir jetzt haben ist ein Rechteck an der Position x: 50, y: 50 mit einer Breite/Höhe von 100/100 mit abgerundeten Ecken (Radius: 5) das man mit der Maus verschieben kann. Das ganze lässt sich auch mit deutlichweniger Code bewerkstelligen, &#8230;</p>
<pre>
var c = paper.rect(10, 10, 50, 50);
c.drag(function (dx, dy) {
    this.attr({x: this.ox + dx, y: this.oy + dy});
}, function () {
    this.ox = this.attr("x");
    this.oy = this.attr("y");
    this.attr({opacity: .5});
}, function () {
    this.attr({opacity: 1});
});
</pre>
<p>&#8230;jedoch ist das zur besseren Veranschaulichung der weiteren Beispiele nützlich etwas ausführlicher den Programmcode zu strukturieren. Eine Untersuchung des Elements mit dem Firebug ergibt folgendes Markup:</p>
<pre>&lt;rect x="50" y="50" width="100" height="100" r="5" rx="5" ry="5"
  fill="#336699" stroke="#000" style="opacity: 1;" opacity="1"/&gt;
</pre>
<p>Als nächstes soll man das Rechteck in der Größe verändern können. Dafür benötigt das Rechteck einen Anfasser Punkt, den wir innerhalb des Rechtecks unten rechts platzieren. Für die neue Funktionalität erzeuge ich ein MovableResizableRectangle Element, das ein MovableRectangle kapselt. unser Anfasserpunkt wird ein RectangleResizer Element. Zunächst der Code des JavaScript Konstrukts MovableResizableRectangle:</p>
<pre>var MovableResizableRectangle = function () {

    var _raphael = null;
    var _movableRectangle = null;
    // der Anfasserpunkt
    var _resizer = null;
    var _instance = null;

    return {

        init: function (r, x, y, width, height, curve) {
            _raphael = r;

            _movableRectangle = new MovableRectangle();
            _movableRectangle.init(r, x, y, width, height, curve)
            _movableRectangle.getSvgObj().drag(this.move, this.start, this.up);
            _movableRectangle.register(this);

            _resizer = new ResizerRectangle();
            _resizer.init(r, (x + width - 15), (y + height - 15), 10, 10, 3);
            // Der Anfasserpunkt muss wissen wen er verändern soll
            _resizer.setResizable(this);
            _resizer.setAttr('fill', '#ff6633');
            _resizer.setAttr('stroke', 'none');

            _instance = this;
        },

        getSvgObj: function () {
            return _movableRectangle.getSvgObj();
        },

        setAttr: function (key, value) {
            _movableRectangle.setAttr(key, value);
        },

        setWidth: function (width) {
            _movableRectangle.setWidth(width);
        },

        getWidth: function () {
            return _movableRectangle.getWidth();
        },

        setHeight: function (height) {
            _movableRectangle.setHeight(height);
        },

        getHeight: function () {
            return _movableRectangle.getHeight();
        },

        setOldWidth: function (oldWidth) {
            _movableRectangle.setOldWidth(oldWidth);
        },

        getOldWidth: function () {
            return _movableRectangle.getOldWidth();
        },

        setOldHeight: function (oldHeight) {
            _movableRectangle.setOldHeight(oldHeight);
        },

        getOldHeight: function () {
            return _movableRectangle.getOldHeight();
        },

        render: function () {
            _movableRectangle.render();
        },

        start: function (param) {
            _movableRectangle.start(param);
        },

        move: function (deltaX, deltaY) {

            var xValue = _movableRectangle.getOldX() + deltaX;
            var yValue = _movableRectangle.getOldY() + deltaY;

            _movableRectangle.setX(xValue);
            _movableRectangle.setY(yValue);

            _movableRectangle.render();

            // Dem Anfasserpunkt die neuen Koordinaten mitteilen
            _resizer.setX(_movableRectangle.getX() + _movableRectangle.getWidth() - 15);
            _resizer.setY(_movableRectangle.getY() + _movableRectangle.getHeight() - 15);
            _resizer.render()
        },

        up: function (event) {
            _instance.setAttr("opacity", 1);
        }
    };
};
</pre>
<p>In der Methode init() wird neben dem MovableRectangle Objekt auch das RectangleResizer Objekt erzeugt &#8211; der Anfasserpunkt. Wenn an dem gezogen oder geschoben wird, soll dieser das MovableResizableRectangle Objekt in der Größe verändern. Dafür werden Getter und Setter für die Breite und Höhe benötigt. Damit das MovableRectangle auch weiß was es verändern soll, bekommt es einen Setter spendiert, setResizable(). Damit das RectangleResizer auch immer schön unten rechts in der Ecke verbleibt wenn am MovableResizableRectangle hin und her geschoben wird, muss das MovableResizableRectangle in der Methode move() dafür sorgen, dass die Positionierung des RectangleResizer neu berechnet und aktualisiert wird.</p>
<pre>var RectangleResizer = function () {

    var _raphael = null;
    var _movableRectangle = null;
    // das Objekt das in der Größe verändert werden soll
    var _resizable = null;
    var _instance = null;

    return {

        init: function (r, x, y, width, height, curve) {
            _raphael = r;
            // auch der Resizer kapselt ein MovableRectangle
            _movableRectangle = new MovableRectangle();
            _movableRectangle.init(r, x, y, width, height, curve)
            _movableRectangle.getSvgObj().drag(this.move, this.start, this.up);
            _instance = this;
        },

        setResizable: function (resizable) {
            _resizable = resizable;
        },

        getResizable: function () {
            return _resizable;
        },

        setAttr: function (key, value) {
            _movableRectangle.setAttr(key, value);
        },

        render: function () {
            _movableRectangle.render();
        },

        setX: function (x) {
            _movableRectangle.setX(x);
        },

        getX: function () {
            return _movableRectangle.getX();
        },

        setY: function (y) {
            _movableRectangle.setY(y);
        },

        getY: function () {
            return _movableRectangle.getY();
        },

        start: function (param) {
            _movableRectangle.start(param);
            // "merken" der Breite/Höhe des Objekts das in der Größe verändert werden soll
            _resizable.setOldWidth(_resizable.getWidth());
            _resizable.setOldHeight(_resizable.getHeight());
        },

        move: function (newX, newY) {
            // aktualisieren des Objekts das in der Größe verändert werden soll
            _resizable.setWidth(_resizable.getOldWidth() + newX);
            _resizable.setHeight(_resizable.getOldHeight() + newY);
            _resizable.render();
        },

        up: function (event) {
            _movableRectangle.up(event);
        }
    };
};
</pre>
<p>Auf diese (zugegebener Maßen experimentelle) Weise kann man weitere Elemente wie Kreise, Ellipsen, Pfade, etc. Kapseln und mit zusätzlicher Funktionalität erweitern. Für eine Real-Life Anwendung sollte man in Erwägung ziehen wie in der Doku beschrieben die JavaScript Bibliothek Plugin ähnlich zu erweitern wie hier: <a href="http://raphaeljs.com/reference.html#plugins-canvas">http://raphaeljs.com/reference.html#plugins-canvas</a> und hier <a href="http://raphaeljs.com/reference.html#plugins-elements">http://raphaeljs.com/reference.html#plugins-elements</a> beschrieben.</p>
<p>Anbei ein <a href="http://www.wortzwei.de/blogzwei/wp-content/uploads/2011/01/experimentalSvgWithRaphaelJS-v0.2.zip">ZIP-Archiv</a> mit einigen Beispielen (zugegebener Maßen experimentell <img src='http://www.wortzwei.de/blogzwei/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> ).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.wortzwei.de/blogzwei/2011/01/vektorgrafiken-mit-raphael/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Solr-Search-Plugin 1.0 out now!</title>
		<link>http://www.wortzwei.de/blogzwei/2011/01/solr-search-plugin-1-0-out-now/</link>
		<comments>http://www.wortzwei.de/blogzwei/2011/01/solr-search-plugin-1-0-out-now/#comments</comments>
		<pubDate>Tue, 18 Jan 2011 13:08:31 +0000</pubDate>
		<dc:creator>dirk</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[google-code]]></category>
		<category><![CDATA[GPL]]></category>
		<category><![CDATA[Labs]]></category>
		<category><![CDATA[Mantis]]></category>
		<category><![CDATA[MantisBT]]></category>
		<category><![CDATA[Open-Source]]></category>
		<category><![CDATA[OpenSource]]></category>
		<category><![CDATA[OS]]></category>
		<category><![CDATA[solr]]></category>

		<guid isPermaLink="false">http://www.wortzwei.de/blogzwei/?p=745</guid>
		<description><![CDATA[Da die Volltextsuche von MantisBT leicht zu wünschen übrig lässt haben wir uns entschlossen ein eigenes Plugin für Mantis zu schreiben. Das Plugin implementiert eine Volltextsuche mit Hilfe von Apache-Solr. Es muss also ein Solr-Server installiert werden da dieser den Index enthält. Da wir sicher nicht die einzigen sind die eine Volltextsuche vermissen haben wir [...]]]></description>
			<content:encoded><![CDATA[<p>Da die Volltextsuche von <a href="http://www.mantisbt.org/">MantisBT</a> leicht zu wünschen übrig lässt haben wir uns entschlossen ein eigenes Plugin für Mantis zu schreiben. Das Plugin implementiert eine Volltextsuche mit Hilfe von <a href="http://lucene.apache.org/solr/">Apache-Solr</a>. Es muss also ein Solr-Server installiert werden da dieser den Index enthält.</p>
<p>Da wir sicher nicht die einzigen sind die eine Volltextsuche vermissen haben wir uns entschlossen das Plugin unter GPL (v3) zu veröffentlichen. Damit wir auch gleich die für ein Open-Source benötigte Infrastruktur bereit stellen können haben wir das Projekt auf <a href="http://code.google.com/">Google Code</a> veröffentlicht. So hat man gleich alles was man benötigt.</p>
<p>Ihr findet das Projekt unter <a href="http://code.google.com/p/solr-search-plugin/">http://code.google.com/p/solr-search-plugin/</a>.</p>
<p><b>Wir hoffen, dass ihr die neue Suche genau so nützlich findet wie wir!</b></p>
]]></content:encoded>
			<wfw:commentRss>http://www.wortzwei.de/blogzwei/2011/01/solr-search-plugin-1-0-out-now/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

