<?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>knallisworld &#187; Empfehlungen</title> <atom:link href="http://www.knallisworld.de/blog/category/empfehlungen/feed/" rel="self" type="application/rss+xml" /><link>http://www.knallisworld.de/blog</link> <description>Where is the beef?</description> <lastBuildDate>Thu, 02 Feb 2012 23:10:07 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <item><title>Migration von Trac zu JIRA</title><link>http://www.knallisworld.de/blog/2011/08/07/migration-von-trac-zu-jira/</link> <comments>http://www.knallisworld.de/blog/2011/08/07/migration-von-trac-zu-jira/#comments</comments> <pubDate>Sun, 07 Aug 2011 12:57:53 +0000</pubDate> <dc:creator>knalli</dc:creator> <category><![CDATA[Howtos]]></category> <category><![CDATA[Management]]></category> <category><![CDATA[Tutorial]]></category> <guid
isPermaLink="false">http://www.knallisworld.de/blog/?p=1391</guid> <description><![CDATA[EinfÃ¼hrung von Atlassians Confluence, FishEye und JIRA In diesem Artikel geht es um die Installation und Konfiguration von Atlassians JIRA, FIshEye und Confluence in einer ursprÃ¼nglich rein Trac-basierten Umgebung. Ich gehe davon aus, dass die Hersteller-Guides bereits bekannt sind oder bei Fragen zu Rate gezogen werden. Es werden nicht alle Funktionen und Features der Produkte [...]]]></description> <content:encoded><![CDATA[<h2>EinfÃ¼hrung von Atlassians Confluence, FishEye und JIRA</h2><p>In diesem Artikel geht es um die Installation und Konfiguration von Atlassians JIRA, FIshEye und Confluence in einer ursprÃ¼nglich rein Trac-basierten Umgebung.</p><p>Ich gehe davon aus, dass die Hersteller-Guides bereits bekannt sind oder bei Fragen zu Rate gezogen werden. Es werden nicht alle Funktionen und Features der Produkte im einzelnen vorgestellt oder erklÃ¤rt (etwa: Was ist ein Crowd-Server? oder Wie stelle ich den Benutzer-Signup aus?).</p><ul><li>http://confluence.atlassian.com/display/JIRA/JIRA+Documentation</li><li>http://confluence.atlassian.com/display/FISHEYE/FishEye+Documentation+Home</li><li>http://confluence.atlassian.com/display/DOC/Confluence+Documentation+Home</li></ul><h3>Installationen</h3><p>FÃ¼r eine saubere Installation empfiehlt es sich, die Anwendungen von einander getrennt zu installieren.</p><p>Alle drei Produkte lassen sich als Standalone oder als WAR herunterladen und installieren. WÃ¤hrend die WAR -Variante nur in einen vorhandenen Tomcat deployt wird, ist die Standalone-Variante eine fertig konfigurierte Einheit, die auch entsprechend korrekt konfiguriert ist. Aus mehreren GrÃ¼nden ist die Standalone-Variante vorzuziehen: Service-Able, besseres Tuning im Performance-Problemfall.</p><p>Leider ist die QualitÃ¤t der Standalone-Versionen nicht Ã¼berall gleich; JIRA ist dabei am Besten und quasi vollstÃ¤ndig.</p><p>FÃ¼r diesen Beitrag installieren wir die Produkte jeweils in die drei Verzeichnisse /opt/confluence, /opt/fisheye und /opt/jira. Und natÃ¼rlich unter Linux.</p><h4>JIRA</h4><p>Praktischerweise wird JIRA in einem selbstausfÃ¼hrenden Installer zur VerfÃ¼gung gestellt. Also sudo gestartet, sollte man hier den empfohlenen Weg nehmen und JIRA als Service mit eigenem Benutzer installieren. Da der Installer selbststÃ¤ndig einen Benutzer jira anlegen wird, sollte dieser nicht vorher schon existieren. Ist bereits einer vorhanden, legt der Installer jira1 an, inkl. einem gleichlautenden Service.</p><p>Danach ist JIRA installiert und muss via Web konfiguriert werden. FÃ¼r die produktive Installation bedeutet dies beispielsweise eine externe Datenbankanbindung.</p><p><strong>Hinweis:</strong> Sofern der Administratorzugang mit einem Benutzer aus dem spÃ¤teren Trac-Import matchen soll, sollte der Benutzername gleich heiÃŸen.</p><p><strong>Hinweis:</strong> Sollen mehrere Tomcats auf einer Maschine laufen, mÃ¼ssen die Ports entsprechend verÃ¤ndert werden. Die JIRA-Tomcat-Konfiguration ist unter conf/server.xml zu finden. Dort findet sich auch ein auskommentierter Connector fÃ¼r AJP.</p><p>Es empfiehlt sich, den Remote- und API-Zugriff sofort zu aktivieren, da dieser in der Regel immer gebraucht wird (etwa fÃ¼r <a
href="http://www.eclipse.org/mylyn/">Eclipse Mylyn</a>).</p><p>Falls die Benutzerkonten zwischen JIRA, Confluence und FishEye synchronisiert werden sollen (und das ist sicher zu empfehlen): Das Feature heiÃŸt bei Atlassian Crowd und ist in allen ProduktenÂ implementiert. Hierbei spielt JIRA dann den Crowd-Server, d.h. es stellt die Konten und PasswÃ¶rter zur VerfÃ¼gung. Confluence und FishEye werden spÃ¤ter nur passiv gespiegelt.</p><h4>FishEye</h4><p>FishEye wird im Gegensatz zu JIRA nicht mit einem Installer ausgeliefert. Das Archiv entpackt hinterlÃ¤sst nur die Applikation. Da der Standardport von FishEye 8060 ist und sich damit selten mit anderen Diensten Ã¼berschneidet, kann man dies so stehen lassen.</p><p>Da FishEye von sich aus kein Service-Script mitliefert, muss man das selber beisteuern. AuÃŸerdem muss man sich auch selber um einen Benutzer (etwa sinnigerweise fisheye) kÃ¼mmern.</p><p><script src="https://gist.github.com/1130328.js?file=fisheye"></script></p><p>FishEye wird per Default in eine HSQLDB installiert. Im Gegensatz zu JIRA kann man nicht bereits zu Beginn eine alternative Datenbank auswÃ¤hlen. DafÃ¼r kann Fisheye jedoch on the fly via Administration/Database in eine externe Datenbank migriert werden.</p><p>Falls die Crowd-FunktionalitÃ¤t von JIRA verwendet werden soll, muss in der Administration der JIRA-Server als &#8220;Application-Link&#8221; angelegt werden. AnschlieÃŸend kann man die BenutzerÂ synchronisierenÂ (etwa automatisch jede Stunde) und das lokale Registrieren abschalten.</p><p><strong>Hinweis:</strong> Mit dem FishEye-Administrator-Passwort kommt man immer in die Admin-Backend zurÃ¼ck. Dennoch empfehle ich, einen Login in einem separaten Browser (oder einfach imÂ Inkognito-Modus) auszuprobieren. Per Default werden Benutzer, die in der Gruppe jira-administrators sind, auch automatisch FishEye-Administratoren.</p><p>Erst nach Abschluss dieser Feinheiten lohnt sich das Anlegen von Repositories.</p><p><strong>Hinweis:</strong> LÃ¤sst man die alte Trac-Installation noch weiter laufen, so kann man in den Eigenschaften eines FishEye-Repositories einen Linker definieren, damit in Commits erscheinenden Ticket-Referenzen (#123) auf Trac verweisen kÃ¶nnen (regulÃ¤res Muster: #(\d+)). Prinzipiell kann man auch einen Link auf FishEye selber erzeugen, das funktioniert natÃ¼rlich nur, wenn keine Tickets aufgrund von Projekt-Splittung verschoben wurden.</p><p>Nach erfolgtem Anlegen und Indizieren des Repositorys (oder der Repositories) sollte der Ãœbersichtlichkeit wegen Projekte anlegen &#8212; idealerweise in der gleichen Struktur wie unter JIRA. AnschlieÃŸend kann man mit den Application-Links dafÃ¼r sorgen, dass erstens FishEye weiÃŸt, dass ein ein bestimmtes Projekt einer JIRA-Installation in den Changeset-Kommentaren verlinkbar ist und zweitens der entsprechenden JIRA-Installation eine Backreferenz auf diese FishEye-Quelle geben.</p><p>Mit dieser Konfiguration werden Commits mit einem Verweis auf ein Ticket (&#8220;&#8230; PROJECTKEY-123&#8230;&#8221;) automatisch auf JIRA verlinkt und gleichzeitig im JIRA-Vorgang als AktivitÃ¤t aufgelistet.</p><h4>Confluence</h4><p>Wie FishEye bietet auch Confluence nur ein entpacktes Verzeichnis an. Auch hier muss man sich um ein Service-Script und einen Benutzer selber kÃ¼mmern.</p><p><script src="https://gist.github.com/1130328.js?file=confluence"></script></p><p>Auch hier sollte man nach erfolgter Installation die Authentifizerung auf JIRA umstellen. DafÃ¼r muss man eine Referenz auf JIRA anlegen. Eventuell ist es auch nÃ¶tig, eine zusÃ¤tzliche Referenz seitens JIRA auf Confluence (erlaubte Abfrage der Konten) anzulegen.</p><p><strong>Wichtiger Hinweis:</strong> Es ist dringendst zu empfehlen, vor dem Switch auf den JIRA-Crowd-Server dem eigenen Konto (in JIRA) die neu zu erstellenden Benutzergruppe confluence-administrators hinzuzufÃ¼gen &#8212; ansonsten sperrt man sich sofort aus. Hat man den Abgleichtimer auf eine Stunde gestellt und will &#8211; fÃ¼r Confluence &#8211; nicht von vorne anfangen, ist man eine Stunde merkbefreit.</p><h3>Von Trac nach JIRA</h3><h4>Upgrade auf Trac 0.12</h4><p>Das Importwerkzeug von JIRA ist nur mit Trac-Export-Daten kompatibel, die aus einer 0.12-Installation heraus erstellt wurden.</p><p>Die vorhandene Trac-Installation lief leider noch in der VorgÃ¤ngerversion 0.11. Das macht sich unter anderem daran bemerkbar, das zwar der Import prinzipiell funktioniert, aber beispielsweise alle Zeiten/Zeitstempel falsch sind (01. Januar 1970). Dieser Umstand wird durch eine Ã„nderung der internen Speicherung von Timestamps in Trac geschuldet (0.11 speichert in Sekunden, 0.12 jedoch in Mikrosekunden).</p><p>Daher war es zunÃ¤chst erforderlich, die vorhandene Trac-Installation mittels Upgrade auf 0.12 zu aktualisieren. Je nach Installation ist ein <a
href="http://trac.edgewall.org/wiki/0.12/TracUpgrade">Upgrade einfach oder umstÃ¤ndlich</a>.</p><p>Hinweis: Es kann durchaus sinnvoll sein, dass man seine bisherige Trac-Installation unverÃ¤ndert lassen will. Dies ist relativ einfach zu bewerkstelligen. Auf einerÂ separatenÂ Maschine (dafÃ¼r eignet sich auch ein schnell aufgezogenes Debian in der VM) wird Trac 0.12 etwa via apt-get installiert. Danach wird ein Trac-Repository konfiguriert und anschlieÃŸend das existierende Repository 1:1 herÃ¼berkopiert. Die anschlieÃŸenden Befehle <em>trac-admin upgrade</em> und <em>trac-admin wiki upgrade</em> hiefen sowohl die Trac-Datenbank als auch die Wikiseiten auf die neue Version &#8211; fertig!</p><h4>Export von Trac</h4><p>Die Trac-Daten werden wie folgt exportiert: Die Tickets liegen alle in einer Datenbank im Repository, die Attachments liegen als Dateistruktur ebenfalls im Repository. Man wechselt in das Verzeichnis vom Trac-Repository und packt alles zusammen in ein Zip-Archiv.</p><h4>Import in JIRA</h4><p>Im Import-Assistenten wÃ¤hlt man Trac und danach das zuvor erstellte Zip-Archiv. Je nach GrÃ¶ÃŸe kann es erforderlich sein, dass man in der JIRA-Administration das Upload-Limit fÃ¼r Dateien (kurzfristig) erhÃ¶hen muss. Der Assistent entpackt das Archiv und analysiert die Strukturen. Sofern man keine Besonderheiten hat, kann man die Schritte alle absegnen. Eventuelle CustomFields sollten ebenfalls als solche auch in JIRA eingefÃ¼gt werden.</p><h4>Das &#8220;No-Priority&#8221;-Issue</h4><p>Beim Import der Ticket-Daten wurde das Feld Priority nicht korrekt Ã¼bernommen. Das hat die Auswirkung, dass beim Editieren eines Tickets automatisch die erstbeste PrioritÃ¤t seitens JIRA verwendet wird. Und das ist 1 =&gt; Blocker. Etwas unschÃ¶n.</p><p>Prinzipiell ist so etwas aber kein groÃŸer Aufwand, da JIRA ein sehr ausgeklÃ¼geltes und vor allem funktionierendes Mehrfachbearbeitungsmanagement mitliefert. Ãœber &#8220;VorgÃ¤nge / Suchen / Erweitert&#8221; kann man mittes JQL eine sehr spezifische Abfrage nach VorgÃ¤ngen machen. Ãœber jede getÃ¤tigte Abfrage lÃ¤sst sich Ã¼ber den Button &#8220;Tools&#8221; in der rechten, oberen Ecke eine Mehrfachbearbeitung starten.</p><p><strong>Hinweis:</strong> Da der Name des Trac-Felds &#8220;Priority&#8221; mit dem JIRA-Feld &#8220;Priority&#8221; konkurriert, hat der Importer ein generisches Feld (cf-xxxx) anlegt.</p><p>Ãœber die Abfrage &#8220;status = Reopened and priority is empty and cf[xxxxx] = Blocker&#8221; lassen sich beispielsweise alle &#8220;prioritÃ¤tslosen&#8221; Tickets abfragen, die aus Trac mit Blocker-PrioritÃ¤t kommen&#8221;. Ãœber die Mehrfachbearbeitung setzt man dann die PrioritÃ¤t auf &#8220;Blocker&#8221;. Das gleiche fÃ¼r alle anderen PrioritÃ¤ten.</p><h4>Das &#8220;Reopened Issues&#8221;-Issue</h4><p>Beim Import der Ticket-Daten wurden alle bereits geschlossenen und &#8220;resolved&#8221; Tickets mit dem Status &#8220;Reopened&#8221; eingeladen. Auch hierfÃ¼r eignet sich die Mehrfachbearbeitung.</p><p><strong>Hinweis:</strong> Der Workflow erfordert beim SchlieÃŸen eines Vorgangs die Angabe einer Resolution. Daher ist es wie bei &#8220;No-Priority&#8221; empfehlenswert, die Abfrage gruppiert nach eine Trac-Resolution zu machen. Ansonsten verliert man die originale Resolution.</p><h3>Von Trac nach Confluence</h3><h4>Export von Trac</h4><p>Die Daten der Wiki-Seiten liegen als Dateistruktur im Trac-Repository. Da der Export bereits unter &#8220;Von Trac nach JIRA&#8221; erfolgt ist, hat man die Wiki-Daten bereits vorliegen.</p><h4>Import in Confluence</h4><p>FÃ¼r den Import der Daten steht ein universelles Java-Programm zur VerfÃ¼gung (ist in der Confluence-Administration unter Import zu finden). Damit lassen sich die Trac-Daten (aber auch noch eine ganze Reihe anderer Formate/Anwendungen) in das Confluence-Schema importieren. Das Programm ist etwas unglÃ¼cklich designed und die Steuerung ist an einigen Punkten etwas unsauber implementiert &#8212; sofern man jedoch einiges beachtet, funktioniert alles einwandfrei.</p><p>ZunÃ¤chst wÃ¤hlt man in der Liste &#8220;trac&#8221; aus. Danach wÃ¤hlt man den Ordner der Attachments aus, was voraussetzt, das man das Trac-Repository auf dem Rechner zur VerfÃ¼gung stehen hat, auf welchem der Importer ausgefÃ¼hrt wird. AnschlieÃŸend wÃ¤hlt man die Wiki-Seiten aus. Hierbei ist anzumerken, dass der Importer den kompletten, absoluten Pfad der Dateien Ã¼bernimmt! Das ist Ã¤uÃŸerst unschÃ¶n, weil man zwar in Confluence spÃ¤ter zwar einzelne, aber nicht mehrere Seiten gleichzeitig verschieben kann. Unter UmstÃ¤nden kann es sinnvoll sein, die Wiki-Seiten fÃ¼r diesen Import kurzfristig auf einem /-Level anzulegen. Ein Unding ohnegleichens.</p><p>Nach der Angabe der Confluence-Server-Angaben werden die Daten importiert. Hinweis: Die externe API muss in Confluence selbstverstÃ¤ndlich aktiviert sein.</p><h2>Bonus</h2><h3>Hudson/Jenkins-Integration</h3><p>Zwar bietet Atlassian natÃ¼rlich eine perfekte Integration in und mit ihrem eigenen Buildserver <a
href="http://www.atlassian.com/software/bamboo/">Bamboo</a> an, dies ist aber nicht zwingend erforderlich. In der Regel reicht es aus, wenn man im Ticket automatisch/sofort erkennen kann, mit welchem Build ein Ticket bzw. ein entsprechender Changeset aufgenommen wurde. DafÃ¼r gibt es das Jenkins <a
href="https://wiki.jenkins-ci.org/display/JENKINS/JIRA+Plugin">JIRA-Plugin</a>.</p><p>Zuallererst muss in der globalen Konfiguration von Jenkins die JIRA-Installation konfiguriert werden. In den meisten FÃ¤llen muss dafÃ¼r ein Benutzer angegeben werden: Will man es schÃ¶n und sauber, dann legt man unter JIRA einen eigenen Buildserver-Benutzer an (etwa mit schÃ¶nem Avatar?) und trÃ¤gt dessen Zugangsdaten (generisches, langes Passwort?) in der Jenkins-Konfiguration ein.</p><p>Danach kann man im entsprechenden Jenkins-Job das JIRA-Plugin aktivieren und weiteres Tuning machen.</p><p>Mit dieser Konfiguration wird ein Build als weitere AktivitÃ¤t in einem JIRA-Vorgang auftauchen.</p> ]]></content:encoded> <wfw:commentRss>http://www.knallisworld.de/blog/2011/08/07/migration-von-trac-zu-jira/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Eine Jar (OJDBC) nachtrÃ¤glich in die Ziel-Jar integrieren</title><link>http://www.knallisworld.de/blog/2010/11/23/eine-jar-ojdbc-nachtraglich-in-die-ziel-jar-integrieren/</link> <comments>http://www.knallisworld.de/blog/2010/11/23/eine-jar-ojdbc-nachtraglich-in-die-ziel-jar-integrieren/#comments</comments> <pubDate>Tue, 23 Nov 2010 18:00:36 +0000</pubDate> <dc:creator>knalli</dc:creator> <category><![CDATA[Java]]></category> <category><![CDATA[Technik]]></category> <category><![CDATA[Tutorial]]></category> <guid
isPermaLink="false">http://www.knallisworld.de/blog/?p=1318</guid> <description><![CDATA[FÃ¼r das visualDependencies-Projekt stand ich eben vor dem Problem, dass zur Laufzeit ein Oracle-JDBC-Treiber benÃ¶tigt wird. Leider kann man ihn jedoch nicht als AbhÃ¤ngigkeit konfigurieren, da zum einen das Projekt unter der GPL lÃ¤uft, und zum anderen es Ã¼berhaupt keinen offiziellen Weg dafÃ¼r gibt. FÃ¼r den eigenen Buildprozess kann man selbstverstÃ¤ndlich ein lokales Repository nutzen, [...]]]></description> <content:encoded><![CDATA[<p>FÃ¼r das visualDependencies-Projekt stand ich eben vor dem Problem, dass zur Laufzeit ein Oracle-JDBC-Treiber benÃ¶tigt wird. Leider kann man ihn jedoch nicht als AbhÃ¤ngigkeit konfigurieren, da zum einen das Projekt unter der GPL lÃ¤uft, und zum anderen es Ã¼berhaupt keinen offiziellen Weg dafÃ¼r gibt. FÃ¼r den eigenen Buildprozess kann man selbstverstÃ¤ndlich ein lokales Repository nutzen, das Artefakt lokal deployen bzw. den Buildserver entsprechend konfigurieren.</p><p>Da jedoch das Projekt im Form des Sourcecodes &#8220;fÃ¼r alle&#8221; erreichbar sein soll, fallen diese Optionen zumindest fÃ¼r diese Situationen weg. Es muss also eine MÃ¶glichkeit geben, den OJDBC-Treiber nachtrÃ¤glich in das fertige Applikations-Jar zu integrieren. Und ja, das ist eigentlich sehr trivial.</p><p>Im folgenden Ant-Script werden sowohl die Applikations-Jar (visualDependencies.one-jar.jar) als auch der JDBC-Treiber (ojdbc14.jar) in der Konfiguration vorbelegt. SelbstverstÃ¤ndlich kann man alle Properties Ã¼berschreiben bzw. das Script entsprechend anpassen.</p><p>Die wichtigen Teile sind: Das Ant-Jar-Command muss den Zusatz &#8220;update&#8221; erhalten, denn die Ziel-Jar soll nicht ersetzt werden. AuÃŸerdem muss ein Fileset mit einer Verzeichnisstruktur angegeben werden, da die Treiber-Jar innerhalb der Ziel-Jar im Verzeichnis lib liegen muss (Struktur einer One-Jar). Das war&#8217;s.</p><p>Hinweis: Das Ant-File ist fÃ¼r den Gebrauch in einer Maven-Umgebung konfiguriert (basedir=../../../ entspricht dem Root-Verzeichnis bei der Annahme, dass Script unter src/main/scripts/ liegt).</p><pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project name=&quot;visualDependencies&quot; default=&quot;help&quot; basedir=&quot;../../../&quot;&gt;
	&lt;!-- The path of the actual artifact (project name), without the file suffix. --&gt;
	&lt;property name=&quot;project.name&quot; value=&quot;visualDependencies.one-jar&quot; /&gt;
	&lt;!-- The path of the ojdbc driver, without the file suffix. --&gt;
	&lt;property name=&quot;ojdbc.name&quot; value=&quot;ojdbc14&quot; /&gt;
	&lt;!-- DO NOT CHANGE THIS LINES UNLESS YOU KNOW WHAT YOU DO! --&gt;
	&lt;property name=&quot;project.jar&quot; value=&quot;${project.name}.jar&quot; /&gt;
	&lt;property name=&quot;ojdbc.jar&quot; value=&quot;${ojdbc.name}.jar&quot; /&gt;
	&lt;!-- Set actual paths of artifacts. --&gt;
	&lt;property name=&quot;application.path&quot; location=&quot;${basedir}/target/${project.jar}&quot; /&gt;
	&lt;property name=&quot;ojdbc.parent.path&quot; location=&quot;${basedir}/oracle&quot; /&gt;
	&lt;property name=&quot;ojdbc.path&quot; location=&quot;${ojdbc.parent.path}/lib/${ojdbc.jar}&quot; /&gt;
	&lt;!-- Shows help (default target) --&gt;
	&lt;target name=&quot;help&quot;&gt;
		&lt;echo message=&quot;See http://www.knallisworld.de/blog/2010/11/23/eine-jar-ojdbc-nachtraglich-in-die-ziel-jar-integrieren/&quot; /&gt;
		&lt;echo message=&quot;Usage: attachOJDBC&quot; /&gt;
	&lt;/target&gt;
	&lt;!-- Checks if the artifacts are available. Throws exceptions if they not exist. --&gt;
	&lt;target name=&quot;checkDependencies&quot;&gt;
		&lt;available file=&quot;${application.path}&quot; property=&quot;application.exists&quot; /&gt;
		&lt;available file=&quot;${ojdbc.path}&quot; property=&quot;ojdbc.exists&quot; /&gt;
		&lt;fail unless=&quot;application.exists&quot; message=&quot;The application file (${application.path}) does not exist.&quot; /&gt;
		&lt;fail unless=&quot;ojdbc.exists&quot; message=&quot;The ojdbc file (${ojdbc.path}) does not exist.&quot; /&gt;
	&lt;/target&gt;
	&lt;!-- Integrates all files of ojdbc.parent.path into the target jar. --&gt;
	&lt;target name=&quot;attachOJDBC&quot; depends=&quot;checkDependencies&quot;&gt;
		&lt;jar update=&quot;true&quot; destfile=&quot;${application.path}&quot;&gt;
			&lt;fileset dir=&quot;${ojdbc.parent.path}&quot; /&gt;
		&lt;/jar&gt;
	&lt;/target&gt;
&lt;/project&gt;
</pre>]]></content:encoded> <wfw:commentRss>http://www.knallisworld.de/blog/2010/11/23/eine-jar-ojdbc-nachtraglich-in-die-ziel-jar-integrieren/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>ClickToPlugin</title><link>http://www.knallisworld.de/blog/2010/09/19/clicktoplugin/</link> <comments>http://www.knallisworld.de/blog/2010/09/19/clicktoplugin/#comments</comments> <pubDate>Sun, 19 Sep 2010 19:51:58 +0000</pubDate> <dc:creator>knalli</dc:creator> <category><![CDATA[Empfehlungen]]></category> <guid
isPermaLink="false">http://www.knallisworld.de/blog/?p=1262</guid> <description><![CDATA[Seit ein paar Wochen nutze ich jetzt bereits die Safari Extension ClickToPlugin. Dabei handelt es sich um eine erweiterte Variante der Extension ClickToFlash des gleichen Entwicklers. WÃ¤hrend die Safari-Extension ClickToFlash nur auf das Blocken von Flash abzielt, geht ClickToPlugin weiter und blockiert auch andere Plugins (daher auch der Name): Silverlight, Java, usw. Es wÃ¤re richtig [...]]]></description> <content:encoded><![CDATA[<p>Seit ein paar Wochen nutze ich jetzt bereits die Safari Extension <a
href="http://hoyois.github.com/safariextensions/clicktoplugin/">ClickToPlugin</a>. Dabei handelt es sich um eine erweiterte Variante der Extension <a
href="http://hoyois.github.com/safariextensions/clicktoflash/">ClickToFlash</a> des gleichen Entwicklers.</p><p>WÃ¤hrend die Safari-Extension ClickToFlash nur auf das Blocken von Flash abzielt, geht ClickToPlugin weiter und blockiert auch andere Plugins (daher auch der Name): Silverlight, Java, usw. Es wÃ¤re richtig zu sagen: ClickToPlugin beinhaltet ClickToFlash.</p><p>Gemeinsam haben beide, dass sie ( vor allem bei Flash) reine Flash-Videoplayer versuchen zu erkennen und bei Erfolg in entsprechendes HTML5-Markup umwandelt.</p><p>Dabei konnte ich in den letzten Wochen bemerken, dass es erstaunlich viele Flash-Videoplayer gibt, die eigentlich nur H.264-Videoquellen abspielen. Daraus folgt glÃ¼cklicherweise, dass der Browser weit aus weniger Flash laden muss (auch auf Anforderung = Click), denn die meisten Videos werden direkt als &#8220;HTML5 &lt;video&gt;&#8221; abgespielt.</p><p>Die Quintessenz: Ungeachtet der [mutmaÃŸlichen] vielen &#8220;Nicht-HTML5-Ready&#8221;-Flash-Inhalten muss man jedoch anmerken, dass die Anzahl wohl tatsÃ¤chlich weitaus geringer ausfallen wÃ¼rde, wenn entsprechende Weichen mehr eingebaut wÃ¼rden.</p> ]]></content:encoded> <wfw:commentRss>http://www.knallisworld.de/blog/2010/09/19/clicktoplugin/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>[Howto] Maven: Wie man eine ausfÃ¼hrbare Jar in eine Java-Webanwendung (War) via Webstart integriert.</title><link>http://www.knallisworld.de/blog/2010/09/04/howto-maven-wie-man-eine-ausfuhrbare-jar-in-eine-java-webanwendung-war-via-webstart-integriert/</link> <comments>http://www.knallisworld.de/blog/2010/09/04/howto-maven-wie-man-eine-ausfuhrbare-jar-in-eine-java-webanwendung-war-via-webstart-integriert/#comments</comments> <pubDate>Sat, 04 Sep 2010 17:06:20 +0000</pubDate> <dc:creator>knalli</dc:creator> <category><![CDATA[Allgemeines]]></category> <category><![CDATA[Empfehlungen]]></category> <category><![CDATA[Java]]></category> <category><![CDATA[Technologie/IT]]></category> <category><![CDATA[Tipps]]></category> <category><![CDATA[jar]]></category> <category><![CDATA[maven]]></category> <category><![CDATA[war]]></category> <category><![CDATA[webstart]]></category> <guid
isPermaLink="false">http://www.knallisworld.de/blog/?p=1225</guid> <description><![CDATA[Die Situation Es bestehen zwei lauffÃ¤hige, fertige Projekte in Maven, welche beide auch vollwertige Artefakte bilden kÃ¶nnen. Zum einen die Webanwendung &#8212; nennen wir sie hier mal webportal &#8212; mit einem WAR-Artefakt, etwa fÃ¼r einen Tomcat. Ob das Artefakt als Snapshot oder Release gemacht wird, ob es nur generiert oder auch in ein Repository deployt [...]]]></description> <content:encoded><![CDATA[<h3>Die Situation</h3><p>Es bestehen zwei lauffÃ¤hige, fertige Projekte in Maven, welche beide auch vollwertige Artefakte bilden kÃ¶nnen.</p><p><a
href="http://www.knallisworld.de/blog/wp-content/uploads/2010/09/Bildschirmfoto-2010-09-04-um-18.52.33.png"></a>Zum einen die Webanwendung &#8212; nennen wir sie hier mal <em>webportal</em> &#8212; mit einem WAR-Artefakt, etwa fÃ¼r einen Tomcat. Ob das Artefakt als Snapshot oder Release gemacht wird, ob es nur generiert oder auch in ein Repository deployt wird, ist hierbei nicht von weiterer Bedeutung.<a
href="http://www.knallisworld.de/blog/wp-content/uploads/2010/09/Nuvola_mimetypes_java_jar.png"><img
class="size-full wp-image-1232 alignright" title="Nuvola_mimetypes_java_jar" src="http://www.knallisworld.de/blog/wp-content/uploads/2010/09/Nuvola_mimetypes_java_jar.png" alt="" width="128" height="128" /></a></p><p>Zum anderen die normale Clientanwendung &#8212; nennen wir sie doch einfach <em>userclient</em> &#8212; mit einem JAR-Artefakt. Wichtig ist natÃ¼rlich, dass hier eine startfÃ¤hige Main-Klasse vorhanden ist. Dies sollte jedoch der Regelfall sein, daher nur der formale Hinweis.</p><p>Zusammengefasst, und der Auftrag an dieses Howto ist also: Wie konfiguriert und erweitert man den Buildzyklus in welchem Projekt an welcher Stelle am geschicktesten, um auf einfachem Wege die JAR-Datei <em>userclient</em> in die Webanwendung <em>webportal</em> als Java Webstart zu integrieren. Dabei ist es hilfreich, wenn man via <em>pom.xml</em> (und natÃ¼rlich der Macht der Properties) die Versionen spezifizieren kann. Der gesamte Prozess von auswÃ¤hlen, signieren und ausliefern soll dabei automatisch und ohne weiteres Eingreifen des Entwicklers geschehen kÃ¶nnen. Idealerweise sollte das ganze auch optional sein &#8212; dazu gibt es dann mehr unter &#8220;Optimierungen und Verbesserungen&#8221;.</p><p><span
id="more-1225"></span></p><h3>Die Grundlagen</h3><p><a
href="http://www.knallisworld.de/blog/wp-content/uploads/2010/09/Bildschirmfoto-2010-09-04-um-18.54.54.png"><img
class="alignleft size-full wp-image-1234" title="Java 6 Webstart" src="http://www.knallisworld.de/blog/wp-content/uploads/2010/09/Bildschirmfoto-2010-09-04-um-18.54.54.png" alt="" width="327" height="145" /></a>Ich mÃ¶chte jetzt nicht viel Ã¼ber die Grundlagen verlieren, nur so viel sei gesagt. Aus Sicht von Maven ist die Konfiguration &#8220;nur&#8221; ein weiteres Plugin von vielen. Daraus ergibt sich natÃ¼rlich auch die MÃ¶glichkeit, via Properties oder Profilen die Konfiguration sehr dynamisch zu halten. Webstart ist eine Technik, die an sich nichts mit Maven zu tun hat. Man kann auch &#8220;hÃ¤ndisch&#8221; seine Jar-Datei Ã¼ber eine URL verfÃ¼gbar machen. Man muss dann jedoch alles selber und richtig machen: Versionisierung, Signierung und Deployment. Die Signierung ist gerade dann wichtig, wenn die Applikation erweiterte/volle Rechte benÃ¶tigt.</p><h3>Die MÃ¶glichkeiten</h3><p>Es gibt eine Reihe von Maven-Plugins, die einen unterschiedliche AnsÃ¤tze und LÃ¶sungen bieten.</p><p>Das <a
href="http://maven.apache.org/plugins/maven-jar-plugin/">Maven Jar Plugin</a> bietet etwa unter anderem die MÃ¶glichkeit, die Jar-Dateien zu signieren. Dies wÃ¤re jedoch nur die halbe Miete, da weder die Jar-Dateien bekannt noch auslieferbar sind. Auch das <a
href="http://mojo.codehaus.org/keytool-maven-plugin/">Keytool plugin</a> ist nicht vollstÃ¤ndig, denn es unterstÃ¼tzt zwar das Keystore gestÃ¼tzte signieren, aber auch nicht mehr. Wohl aber kÃ¶nnen diese Plugin als Basis fÃ¼r andere dienen.</p><p>Weitaus mehr Funktionen kann das <a
href="http://mojo.codehaus.org/webstart/webstart-maven-plugin/">Webstart Maven Plugin</a> bieten. Es gibt verschiedene Arten der Erzeugung der Jnlp-Datei und dem damit verbundenen Sammeln, Bestimmen und Signieren der AbhÃ¤ngigkeiten in Form weiterer Jars oder Classfiles. Es ist auch ein hilfreiches Plugin, wenn man aus einem Projekt heraus direkt Jnlp &amp; Ressourcen erzeugen will.</p><p>In diesem Howto ist aber vor allem ein Ziel von Relevanz:Â Die Variante mit dem Jnlp-Download-Servlet: das Goal <a
href="http://mojo.codehaus.org/webstart/webstart-maven-plugin/jnlp-download-servlet-mojo.html">webstart:jnlp-download-servlet</a>.<a
href="http://www.knallisworld.de/blog/wp-content/uploads/2010/09/jnlp.gif"><img
class="alignright size-full wp-image-1235" title="jnlp" src="http://www.knallisworld.de/blog/wp-content/uploads/2010/09/jnlp.gif" alt="" width="128" height="128" /></a></p><p>Dieses Goal erzeugt im Buildprozess ein weiteres Verzeichnis mit den Ressourcen des <em>userclients</em> und der dazugehÃ¶renden Jnlps. Ein spezielles Servlet Ã¼bernimmt die Auslieferungen.</p><h3>Die Konfiguration im Projekt <em>userclient</em></h3><p>Das Projekt muss und sollte nicht &#8220;wissen&#8221;, dass es Ã¼ber Webstart irgendwo eingebunden wird. Daher sind keine Ã„nderungen nÃ¶tig. Wohl aber muss bekannt sein, wie die aktuelle bzw. die gewÃ¼nschte Version ist und ggf. das Maven-Repository der Deploys.</p><h3>Die Konfiguration im Projekt <em>webportal</em></h3><p><a
href="http://www.knallisworld.de/blog/wp-content/uploads/2010/09/Bildschirmfoto-2010-09-04-um-18.52.33.png"><img
title="Maven" src="http://www.knallisworld.de/blog/wp-content/uploads/2010/09/Bildschirmfoto-2010-09-04-um-18.52.33.png" alt="" width="170" height="50" /></a>Das <em>webportal</em> muss hingegen durchaus von der Existenz des <em>userclients</em> wissen, denn jenes es soll ja in diese Webanwendung integriert werden. Die Konfiguration besteht im Wesentlichen aus drei Schritten: JnlpDownloadServlet-AbhÃ¤ngigkeit einfÃ¼gen, Servlet in der web.xml registrieren und Build-Plugin in der pom.xml konfigurieren.</p><h4>JnlpDownloadservlet (pom.xml)</h4><p>Das Maven-Paket findet sich unter dem Namen <em>com.sun.java.jnlp</em> bzw.Â <em>jnlp-servlet</em> wieder. Als einfache AbhÃ¤ngigkeit ist es damit im Classpath und beispielsweise in der web.xml verwendbar. <a
href="http://coffeebreaks.org/tmp/maven-staging/webstart/site/jnlp101.html">Weitere Informationen.</a></p><pre class="brush: xml; title: ; notranslate">
&lt;dependency&gt;
    &lt;groupId&gt;com.sun.java.jnlp&lt;/groupId&gt;
    &lt;artifactId&gt;jnlp-servlet&lt;/artifactId&gt;
    &lt;version&gt;5.0&lt;/version&gt;
&lt;/dependency&gt;
</pre><h4>web.xml</h4><p>Zur Basiskonfiguration muss nur das Servlet registriert und mit einem URL-Pattern verknÃ¼pft werden. Das klingt trivial, und das ist es auch.</p><pre class="brush: xml; title: ; notranslate">
&lt;servlet&gt;
  &lt;servlet-name&gt;JnlpDownloadServlet&lt;/servlet-name&gt;
  &lt;servlet-class&gt;jnlp.sample.servlet.JnlpDownloadServlet&lt;/servlet-class&gt;
&lt;/servlet&gt;
&lt;servlet-mapping&gt;
  &lt;servlet-name&gt;JnlpDownloadServlet&lt;/servlet-name&gt;
  &lt;url-pattern&gt;/webstart/*&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;</pre><p>Damit wird die URL domain.tld/context/webstart an das Servlet gemappt. Dadurch kann das Servlet auch auf &#8220;virtuelle Dateianfragen&#8221; reagieren, etwa nach Jar-Dateien ohne Versions-Qualifkation (obwohl sie als versionierte Artefakte vorliegen).</p><p>Die Konfiguration lÃ¤sst noch einige Dinge erweitern, verÃ¤ndern und tweaken (siehe Absatz Optimierungen und Verbesserungen). FÃ¼r den Haupteinsatzzweck &#8211; das Bereitstellen einer oder mehrerer Jars via Webstart ist das jedoch vÃ¶llig ausreichend.</p><p><a
href="http://download.oracle.com/javase/6/docs/technotes/guides/javaws/developersguide/downloadservletguide.html">Weitere Informationen bei Oracle/Java</a>.Â Und <a
href="http://mojo.codehaus.org/webstart/webstart-maven-plugin/examples/advanced_jnlp_download_servlet.html">weitere Informationen bei Codehaus</a>.</p><h4>pom.xml</h4><p>Neben der AbhÃ¤ngigkeit des <em>JnlpDownloadServlet</em> muss das eigentlichen <em>Maven Webstart Plugin</em> fÃ¼r seinen Einsatz konfiguriert werden. Das Build-Plugin benÃ¶tigt zudem noch ein Template (fÃ¼r die Generierung der Jnlp), die wird weiter unten beschrieben.</p><p>Zur Grundkonfiguration gehÃ¶rt:</p><ol><li>Wo liegt das Jnlp-Template?</li><li>Wie heiÃŸt der Ausgabename der Jnlp?</li><li>Welche AbhÃ¤ngigkeiten gibt es fÃ¼r das Paket &#8212; hier wÃ¤re das der <em>userclient</em>?</li></ol><p>Des Weiteren lÃ¤sst sich bestimmen, ob etwa weitere (transitive) AbhÃ¤ngigkeiten mitausgeliefert werden sollen (bei Webstart ist das wohl meist sinnvoll), ob die Ressourcen signiert werden sollen und ob alles nochmals komprimiert deployt werden soll. <a
href="http://mojo.codehaus.org/webstart/webstart-maven-plugin/examples/advanced_jnlp_download_servlet.html">Weitere Informationen</a>.</p><p>Prinzipiell ist man weder auf eine AbhÃ¤ngigkeit pro Paket/JNLP beschrÃ¤nkt noch auf eine JNLP pro Plugin-Call geschweige denn des gesamten Projekts. Ãœber das KonfigurationsschlÃ¼sselwort <em>commonJarResources</em> kÃ¶nnen sogar gemeinsam verwendete AbhÃ¤ngigkeiten definiert werden.</p><p>Da der userclient erweiterte Rechte benÃ¶tigt, mÃ¼ssen alle Classfiles und Jars signiert werden. Wahlweise verwendet dafÃ¼r einen vorhandenen Keystore oder erstellt einen neuen. FÃ¼r diese Zwecke wird pro Buildvorgang ein neuer Keystore angelegt, damit signiert und danach wieder gelÃ¶scht.</p><p>Die Execution ist sinnigerweise <em>process-resources</em> mit dem Goal <em>jnlp-download-servlet</em>, denn streng genommen sind es ja nur weitere Ressourcen.</p><pre class="brush: xml; title: ; notranslate">
&lt;plugin&gt;
  &lt;groupId&gt;org.codehaus.mojo.webstart&lt;/groupId&gt;
  &lt;artifactId&gt;webstart-maven-plugin&lt;/artifactId&gt;
  &lt;executions&gt;
    &lt;execution&gt;
      &lt;phase&gt;process-resources&lt;/phase&gt;
      &lt;goals&gt;
        &lt;goal&gt;jnlp-download-servlet&lt;/goal&gt;
      &lt;/goals&gt;
    &lt;/execution&gt;
  &lt;/executions&gt;
  &lt;configuration&gt;
    &lt;outputDirectoryName&gt;webstart&lt;/outputDirectoryName&gt;
    &lt;excludeTransitive&gt;false&lt;/excludeTransitive&gt;
    &lt;jnlpFiles&gt;
      &lt;jnlpFile&gt;
        &lt;templateFilename&gt;template.vm&lt;/templateFilename&gt;
        &lt;outputFilename&gt;UserClient.jnlp&lt;/outputFilename&gt;
        &lt;jarResources&gt;
          &lt;jarResource&gt;
            &lt;groupId&gt;org.example.userclient&lt;/groupId&gt;
            &lt;artifactId&gt;example-userclient&lt;/artifactId&gt;
            &lt;version&gt;1.0.0&lt;/version&gt;
            &lt;mainClass&gt;org.example.userclient.Main&lt;/mainClass&gt;
          &lt;/jarResource&gt;
        &lt;/jarResources&gt;
      &lt;/jnlpFile&gt;
    &lt;/jnlpFiles&gt;
    &lt;outputJarVersions&gt;true&lt;/outputJarVersions&gt;
    &lt;verbose&gt;false&lt;/verbose&gt;
  &lt;/configuration&gt;
&lt;/plugin&gt;
</pre><p>Mit dieser Konfiguration werden die Jar-Dateien inkl. AbhÃ¤ngigkeiten in das Verzeichnis <em>webstart</em> gepackt &#8212; remember? wie in der <em>web.xml</em>. Das Template heiÃŸt <em>template.vm</em> und ist per default unter <em>src/main/jnlp</em> zu finden. Dies lieÃŸe sich mit <em>templateDirectory</em> Ã¼berrschreiben. Der Name der Jnlp lautet <em>UserClient.jnlp</em>, damit ergibt sich die spÃ¤tere Web-Url: <em>http://example.org/context/webstart/UserClient.jnlp</em>. Die eigentlichen Ressourcen und AbhÃ¤ngigkeiten werden in <em>jarResources/jarResource</em> definiert. Bei einfachen Projekten wird dies nur eine Ressource sein, theoretisch wÃ¤ren auch mehrere mÃ¶glich. Die Konfiguration Ã¤hnelt der der <em>dependencies</em>.</p><h4>template.vm</h4><p>Im Prinzip ist das Template eine unfertige Jnlp. Sie wird durch das Maven Plugin mit den endgÃ¼ltigen Daten befÃ¼llt. Da bereits die pom.xml Ã¼ber einige Informationen wie Projektnamen, -beschreibung oder -url verfÃ¼gt, kÃ¶nnen so sehr einfach die Daten mit Ã¼bernommen werden. Man kann jedoch auch die Platzhalter entfernen &#8212; es ist eben nur ein Template.</p><p>Ein Beispiel kÃ¶nnte so aussehen:</p><pre class="brush: xml; title: ; notranslate">
&lt;jnlp spec=&quot;$jnlpspec&quot; codebase=&quot;$$codebase&quot;&gt;
  &lt;information&gt;
    &lt;title&gt;$project.Name&lt;/title&gt;
    &lt;vendor&gt;$project.Organization.Name&lt;/vendor&gt;
    &lt;homepage href=&quot;$project.Url&quot;/&gt;
    &lt;description&gt;$project.Description&lt;/description&gt;
    &lt;icon href=&quot;../resources/images/logo.png&quot;/&gt;
    &lt;icon href=&quot;../resources/images/logo.png&quot; kind=&quot;splash&quot;/&gt;
#if($offlineAllowed)
&lt;offline-allowed/&gt;
#end
  &lt;/information&gt;
#if($allPermissions)
&lt;security&gt;
&lt;all-permissions/&gt;
&lt;/security&gt;
#end
  &lt;resources&gt;
    &lt;j2se version=&quot;$j2seVersion&quot;/&gt;
$dependencies
  &lt;/resources&gt;
  &lt;application-desc main-class=&quot;$mainClass&quot;&gt;&lt;/application-desc&gt;
&lt;/jnlp&gt;
</pre><p>Mehr oder weniger simpel, oder? Eventuell sollte man die Adressen zum Logo anpassen (oder entfernen); gerade die letzte Zeile erzeugt einen netten Splashscreen (Ladebild) wÃ¤hrend dem Starten und Laden der Anwendung. Das ist immer gerne willkommen.</p><p>Wichtig: Im Gegensatz zu dem einen oder anderen Beispiel ist es hierbei wichtig, dass die Variable $$codebase heiÃŸt. Nicht etwa ${codebase}. Insgesamt sind in der JNLP &#8212; sofern man sie Ã¼ber das Servlet ausliefert &#8212; folgende Variablen verfÃ¼gbar: codebase, name, context und site.</p><h3>Optimierungen und Verbesserungen</h3><p
style="text-align: center;"><a
href="http://www.knallisworld.de/blog/wp-content/uploads/2010/09/IMG_0095.jpg"><img
class="aligncenter size-large wp-image-1236" title="IMG_0095" src="http://www.knallisworld.de/blog/wp-content/uploads/2010/09/IMG_0095-1024x475.jpg" alt="" width="768" height="356" /></a></p><h4>&#8220;Einmal signiert, bitte!&#8221;</h4><p>Um <em>all-permissions</em> nutzen zu kÃ¶nnen, mÃ¼ssen die Jars und Classfiles signiert werden. Das erreicht man, indem man unter dem XML-Knoten <em>configuration</em> einen Knoten <em>sign</em> anlegt, etwa:</p><pre class="brush: xml; title: ; notranslate">
&lt;sign&gt;
	&lt;keystore&gt;keystore.ks&lt;/keystore&gt;
	&lt;keypass&gt;pass&lt;/keypass&gt;
	&lt;storepass&gt;pass&lt;/storepass&gt;
	&lt;alias&gt;userclient&lt;/alias&gt;
	&lt;validity&gt;36500&lt;/validity&gt;
	&lt;dnameCn&gt;UserClient&lt;/dnameCn&gt;
	&lt;dnameOu&gt;Software Development&lt;/dnameOu&gt;
	&lt;dnameO&gt;The Example Networks&lt;/dnameO&gt;
	&lt;dnameL&gt;Cologne&lt;/dnameL&gt;
	&lt;dnameSt&gt;NRW&lt;/dnameSt&gt;
	&lt;dnameC&gt;DE&lt;/dnameC&gt;
	&lt;verify&gt;false&lt;/verify&gt;
	&lt;keystoreConfig&gt;
		&lt;delete&gt;true&lt;/delete&gt;
		&lt;gen&gt;true&lt;/gen&gt;
	&lt;/keystoreConfig&gt;
&lt;/sign&gt;
</pre><p>Hierbei wird der Keystore lokal erzeugt (keystoreConfig/gen ist true) und nach Gebrauch wieder gelÃ¶scht (keystoreConfig/delete ist true). SelbstverstÃ¤ndlich kann man hier auch a) noch einen Keystore-Generator (s.o.) nutzen oder einen fest konfigurierten, dauerhaften. Dann sollte man natÃ¼rlich die Konfiguration entsprechend anpassen.</p><h4>&#8220;Bitte Optional&#8221; &#8212; alles in ein Profil</h4><p>Die Profile in der <em>pom.xml</em> sind ein mÃ¤chtiges Werkzeug, um bestimmte Features zusammenzufassen. So kÃ¶nnte man das gesamte Build-Plugin in ein Profil &#8212; etwa mit dem Namen <em>with-webstart</em> &#8212; ablegen.</p><p>Selbst die AbhÃ¤ngigkeit zum JnlpDownloadServlet kann man dorthin verlagern &#8212; wenn man daran denkt, dass in diesem Falle auch die web.xml dynamisch erstellt werden soll.</p><h4>Macht der Properties</h4><p>Man kann die Gesamtkonfiguration um einiges komfortabler machen, indem man Properties einfÃ¼hrt und deren Standardwerte &#8220;oben&#8221; in der <em>pom.xml</em> definiert. Gute Kandidaten hierbei wÃ¤ren: userclient.version, keystore.file, keystore.keypass, keystore.storepass und keystore.alias.</p><h4>Noch mehr in Sachen Jnlp</h4><p>In der <em>web.xml</em> kann des Weiteren das verhalten des JnpDownloadServlet verÃ¤ndert werden. Ein Ãœberblick Ã¼ber einige MÃ¶glichkeiten: Â Mimetypen Ã¤ndern, Dateiendungen Ã¤ndern, weitere Mappings anlegen, spezielles Debugging.</p> ]]></content:encoded> <wfw:commentRss>http://www.knallisworld.de/blog/2010/09/04/howto-maven-wie-man-eine-ausfuhrbare-jar-in-eine-java-webanwendung-war-via-webstart-integriert/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Kleines FritzBox/Netcologne WÃ¤chterscript &#8211; Uptime, Reconnect per Script</title><link>http://www.knallisworld.de/blog/2010/08/28/kleines-fritzboxnetcologne-wachterscript-uptime-reconnect-per-script/</link> <comments>http://www.knallisworld.de/blog/2010/08/28/kleines-fritzboxnetcologne-wachterscript-uptime-reconnect-per-script/#comments</comments> <pubDate>Sat, 28 Aug 2010 16:20:16 +0000</pubDate> <dc:creator>knalli</dc:creator> <category><![CDATA[Empfehlungen]]></category> <guid
isPermaLink="false">http://www.knallisworld.de/blog/?p=1199</guid> <description><![CDATA[Aufgabe: Das automatisierte Auslesen der aktuellen Uptime (Verbindungszeit) der eigenen Internetverbindung und idealerweise auch das &#8220;reconnecten&#8221; per Scriptaufruf. Das NetCologne Router-Modem-Gespann &#8212; welches eine spezielle gebrandete FritzBox ist &#8212; mangelt es etwas an Scripting-MÃ¶glichkeiten. Der einzige Zugriff ist eine WeboberflÃ¤che, die a) nur dÃ¼rftig ist und b) darÃ¼ber hinaus auch noch (wieso eigentlich?!) mit einem [...]]]></description> <content:encoded><![CDATA[<p>Aufgabe: Das automatisierte Auslesen der aktuellen Uptime (Verbindungszeit) der eigenen Internetverbindung und idealerweise auch das &#8220;reconnecten&#8221; per Scriptaufruf.</p><p>Das NetCologne Router-Modem-Gespann &#8212; welches eine spezielle gebrandete FritzBox ist &#8212; mangelt es etwas an Scripting-MÃ¶glichkeiten. Der einzige Zugriff ist eine WeboberflÃ¤che, die a) nur dÃ¼rftig ist und b) darÃ¼ber hinaus auch noch (wieso eigentlich?!) mit einem Sessioncookie &#8220;gesichert ist&#8221;.</p><p>Das hat Folgen. Nachdem man dann per Firebug o.Ã¤. Tools herausgefunden hat, hinter welcher URL sich bspw. die Uptime versteckt, muss man feststellen, dass das Ergebnis des entsprechenden wgets dennoch nur die blÃ¶de Ãœbersichtsseite enthÃ¤lt. Warum? Weil der web.cgi-Controller jedes Mal, wenn keine Session oder ein falscher Referrer Â geschickt wird, immer jene Seite ausgibt. Â Hilfreich war da ein kleines <a
href="http://snippets.dzone.com/posts/show/3937">Snippet</a>.</p><p><a
href="http://www.knallisworld.de/blog/wp-content/uploads/2010/08/Bildschirmfoto-2010-08-28-um-18.17.34.png"><img
class="aligncenter size-medium wp-image-1200" title="NetCologneShellScript 0.0.1" src="http://www.knallisworld.de/blog/wp-content/uploads/2010/08/Bildschirmfoto-2010-08-28-um-18.17.34-300x158.png" alt="" width="300" height="158" /></a></p><p>Herausgekommen ist ein kleines Shell-Script, welches folgende Basics kann:</p><ul><li>uptime &#8211; Ermittlung der aktuellen Zeit</li><li>ipaddr &#8211; Ermittlung der aktuellen IP-Adresse (extern)</li><li>connect, disconnect, reconnect &#8211; Steuern des PPPoE-Devices.</li></ul><p>Ob noch mehr hinzukommt, werden wir mal sehen. Aktuellen/Letzter Telefonanruf mit NamensauflÃ¶sung wÃ¤re so &#8216;ne Idee&#8230;</p><p>Das Script kann man hier laden: <a
href="http://www.knallisworld.de/blog/wp-content/uploads/2010/08/netconnect.sh.zip">netconnect.sh</a></p><p>Entwickelt und getestet wurde es unter einem OS X 10.6 (+ wget), aber sollte eigentlich unter jedem Unix laufen. Naja, und was Windows angeht: MÃ¤dels, besorgt Euch ein ordentliches Betriebssystem <img
src='http://www.knallisworld.de/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> Wahlweise geht sicher auch Cygwin &#8211; wer es braucht.</p> ]]></content:encoded> <wfw:commentRss>http://www.knallisworld.de/blog/2010/08/28/kleines-fritzboxnetcologne-wachterscript-uptime-reconnect-per-script/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Hudson-Konfiguration im SVN</title><link>http://www.knallisworld.de/blog/2010/07/28/hudson-konfiguration-im-svn/</link> <comments>http://www.knallisworld.de/blog/2010/07/28/hudson-konfiguration-im-svn/#comments</comments> <pubDate>Wed, 28 Jul 2010 11:41:20 +0000</pubDate> <dc:creator>knalli</dc:creator> <category><![CDATA[Empfehlungen]]></category> <category><![CDATA[Entwicklung]]></category> <category><![CDATA[Konfiguration]]></category> <category><![CDATA[Technik]]></category> <guid
isPermaLink="false">http://www.knallisworld.de/blog/?p=1150</guid> <description><![CDATA[Keeping your configuration and data in Subversion Auch die Konfiguration des Build-Servers selber sollte man sichern.]]></description> <content:encoded><![CDATA[<p><a
href="http://www.hudson-labs.org/content/keeping-your-configuration-and-data-subversion">Keeping your configuration and data in Subversion</a></p><p>Auch die Konfiguration des Build-Servers selber sollte man sichern.</p> ]]></content:encoded> <wfw:commentRss>http://www.knallisworld.de/blog/2010/07/28/hudson-konfiguration-im-svn/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Howto: Ein firmeneigenes Java-Maven-Repository aufsetzen</title><link>http://www.knallisworld.de/blog/2010/07/06/howto-ein-firmeneigenes-java-maven-repository-aufsetzen/</link> <comments>http://www.knallisworld.de/blog/2010/07/06/howto-ein-firmeneigenes-java-maven-repository-aufsetzen/#comments</comments> <pubDate>Tue, 06 Jul 2010 21:03:12 +0000</pubDate> <dc:creator>knalli</dc:creator> <category><![CDATA[Eclipse]]></category> <category><![CDATA[Empfehlungen]]></category> <category><![CDATA[Entwicklung]]></category> <category><![CDATA[Java]]></category> <category><![CDATA[Technik]]></category> <category><![CDATA[Tutorial]]></category> <guid
isPermaLink="false">http://www.knallisworld.de/blog/?p=1136</guid> <description><![CDATA[FÃ¼r diesen Artikel setze ich jetzt einfach mal voraus, dass die Begriffe und Technologien hinter Java, Maven, Repository, Eclipse und Tomcat bekannt und gelÃ¤ufig sind. Und nein, jeweiliger Profi muss man zum VerstÃ¤ndnis nicht sein. Was wollen wir? An ein firmeneigenes Repository &#8212; oder auch: corporate repository &#8212; gelten besondere Anforderungen. Diese kÃ¶nnen bei einem [...]]]></description> <content:encoded><![CDATA[<p>FÃ¼r diesen Artikel setze ich jetzt einfach mal voraus, dass die Begriffe und Technologien hinter Java, Maven, Repository, Eclipse und Tomcat bekannt und gelÃ¤ufig sind. Und nein, jeweiliger Profi muss man zum VerstÃ¤ndnis nicht sein.</p><h3>Was wollen wir?</h3><p>An ein firmeneigenes Repository &#8212; oder auch: <em>corporate repository</em> &#8212; gelten besondere Anforderungen. Diese kÃ¶nnen bei einem &#8220;einfach privat-eigenen&#8221; verÃ¤ndert werden, aber man kommt meistens auf folgende Punkte:</p><ol><li>Ein Repository soll den Entwicklern zum Deployen der eigenen Artifakte und Module zur VerfÃ¼gung gestellt werden. Wahlweise Ã¼bernimmt dies auch ein automatischer Build-Agent wie <a
href="http://hudson-ci.org/">Hudson</a>, <a
href="http://www.jetbrains.com/teamcity/">TeamCity</a> und haste-nicht-gesehen.</li><li>Ein Repositorymanager soll als p<em>roxy</em> fungieren. In einer Firma spart dies nicht nur einfache Bandbreite. Da ein solcher Manager in der Regel im lokalen Netz steht, sind die Interaktionszeiten um ein Vielfaches besser.</li><li>Ein so genanntes t<em>hird party pepository</em> fÃ¼r die AbhÃ¤ngigkeiten, die unbedingt notwendig sind und wovon es keine Maven-AbhÃ¤ngigkeiten gibt.</li></ol><p>FÃ¼r Punkt zwei spricht auch eine wesentlich einfachere Konfiguration der Clients (Entwicklerprofile), da nur noch ein Repository eingetragen werden muss. Alle &#8220;bekannten&#8221; Repositories werden zentral gebÃ¼ndelt, damit schwindet natÃ¼rlich gleichzeitig die &#8220;Freiheit&#8221; des einzelnen Entwicklers, andere &#8220;unbekannte&#8221; Repositories zu verwenden. Dies ist jedoch vernachlÃ¤ssigbar, weil: Diese &#8220;Freiheit&#8221; schrÃ¤nkt im Endeffekt den Buildprozess und auch die Wiederverwendbarkeit ein. Das HinzufÃ¼gen von weiteren Repositories in die POM ist aus GrÃ¼nden der Versionisierung und Nachhaltigkeit auch keine optimale LÃ¶sung. Dennoch, alles nur <a
href="https://wiki.jasig.org/display/UPM30/Nexus+Proxy+Example">eine Sache der Konfigurations der Clients</a>.</p><h3>Was brauchen wir?</h3><p>Es gibt eine Reihe von Repository-Managern, die allesamt viel kÃ¶nnen. Die Wahl auf <a
href="http://nexus.sonatype.org/">Nexus</a> fÃ¤llt hier aus folgenden GrÃ¼nden:</p><ul><li>der Footprint ist mit 30 Megabyte wesentlich kleiner als bspw. <a
href="http://www.jfrog.org/products.php">Artifactory</a></li><li>die interne Verzeichnisstruktur entspricht mehr oder weniger 1:1 der realen Organisationsstruktur eines Maven-Repositorys (im Vergleich: Artifactory speichert ein eigenes Datenbankstruktur Ã¤hnliches Layout)</li><li>Nexus und das Eclipse-Plugin <a
href="http://m2eclipse.sonatype.org/">m2eclipse</a> sind vom gleichen Hersteller Sonatype und ergÃ¤nzen sich; nach dem Umstellen bemerkt der Entwickler keinen Unterschied in der Suche, Auto-Discovery, o.Ã¤.</li></ul><p>Eine <a
href="http://www.sonatype.com/books/nexus-book/reference/index.html">umfangreiche Online-Dokumentation</a> ist auf der Nexus-Seite zu finden.</p><h3>Installation</h3><p>Nexus wird unter anderem als WAR ausgeliefert, insofern die Installation in einen Tomcat ein leichtes ist. Beachtenswert ist dabei nur, dass Nexus ein Verzeichnis <em>~/sonatype-work</em> erstellt. Da sich dort unter UmstÃ¤nden viele Nutzdaten ansammeln, kann ein Verschieben (symbolischer Link?) nicht verkehrt sein. Da sich mit der Laufe der Zeit einiges an Daten ansammeln kann, sollte der Platz nicht zu sparsam vermessen sein.</p><h3>Umfang</h3><p>Nachdem Tomcat bzw. Nexus gestartet ist, kann man sich mit dem Default-Daten admin/admin123 anmelden (analog Â mit den Daten der anderen beiden Benutzern!).</p><p>Nexus kommt bereits mit einer Reihen von vorkonfigurierten, eigenen <em>hosted repositories</em> einher.</p><ul><li>releases sammelt alle Release-Artifakte der Firma</li><li>snapshots sammelt alle Snapshot-Artifakte der Firma</li><li>third-party sammelt alle Release-Artifakte externer Quellen, wofÃ¼r es keine Maven-Repositories gibt (oder wo man jenes Repository nicht generell zur VerfÃ¼gung stellen will), gutes Beispiel ist ein (aktueller) Oracle-JDBC-Treiber</li></ul><p>Daneben gibt es so genannte <em>proxy repositories</em>, die praktisch gesehen nur aus einem Index bestehen. Wie ein Proxy hÃ¤ngen sie sich zwischen dem Client und dem tatsÃ¤chlichen Repository und <em>cachen</em> alle Artifakte lokal. Selbst der Index ist mehrere Megabytes groÃŸ, das sollte man nicht vernachlÃ¤ssigen. Voreingetragene <em>proxy</em> <em>repositories</em> sind Apache Snapshots, Codehaus Snapshots, Central Maven RepositoryÂ (Maven1/Maven2-Repository-Konverter sind in Nexus vorhanden a.k.a. <em>virtual repositories</em>).</p><p>Die <em>grouped repositories</em> sind auch rein virtuelle Gruppierungen von verschiedenen Repositories. Das Standard Repository &#8220;Public&#8221; ist in der einfachsten Konfiguration eine Sammlung aller (aktivierten) Repositories auf dem Manager &#8212; also sowohl der externen Spiegel, der Third-Parties als auch den eigenen Artifakten.</p><h3>Konfiguration</h3><p>Die Aktivierung und Verwaltung von (neuen) Repositories ist abhÃ¤ngig der eigenen BedÃ¼rfnisse. Meistens sinnvoll ist es jedoch, bei den drei groÃŸen Spiegeln (<em>proxy repositories</em>) in dem Konfigurationstab das Indizieren (Download Remote Indexes) zu aktivieren. Je nach Belieben kann man in der Gruppe Administration auch das Aktualisierungsverhalten steuern.</p><h3>Konfiguration: Deployment</h3><p>Um ein Deployment zu gewÃ¤hrleisten, muss man nebst Kenntnis der Repository-URL (eben <em>die</em> URL) nur wissen, ob der anonyme Zugriff erlaubt sein soll, oder ob man einen Deployment-Benutzer einrichten und nutzen willst. Falls eine Richtlinie vorschreiben sollte, dass dies nur ein Build-Agent machen darf, ist ein (geheimes) Passwort oder SchlÃ¼ssel unabdingbar.</p><h3>Konfiguration: Client</h3><p>Nehmen wir an, der Nexus-Manager ist auf dem Host 192.168.0.10:8080/nexus installiert. In der einfachen Installation und Konfiguration sammeln sich im <em>public repository</em> praktisch alle relevanten Artifakte (sowohl Releases als auch Snapshots).</p><pre class="brush: xml; title: ; notranslate">
&lt;settings&gt;
&lt;mirrors&gt;
&lt;mirror&gt;
&lt;id&gt;corporate&lt;/id&gt;
&lt;name&gt;CorporateÂ Repository&lt;/name&gt;
&lt;url&gt;http://192.168.0.10:8080/nexus/content/groups/public&lt;/url&gt;
&lt;mirrorOf&gt;*&lt;/mirrorOf&gt;
&lt;/mirror&gt;
&lt;/mirrors&gt;
&lt;/settings&gt;
</pre><p>Der Deployment-User benÃ¶tigt ggf. Zugangsdaten fÃ¼r das entsprechende Repository.</p><p>Ein Client wie m2eclipse sollte danach einen kompletten Rebuild des Index machen.</p> ]]></content:encoded> <wfw:commentRss>http://www.knallisworld.de/blog/2010/07/06/howto-ein-firmeneigenes-java-maven-repository-aufsetzen/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Tipp: Douglas Crockford &#8211; The JSON Saga</title><link>http://www.knallisworld.de/blog/2010/06/06/tipp-douglas-crockford-the-json-saga/</link> <comments>http://www.knallisworld.de/blog/2010/06/06/tipp-douglas-crockford-the-json-saga/#comments</comments> <pubDate>Sun, 06 Jun 2010 12:39:45 +0000</pubDate> <dc:creator>knalli</dc:creator> <category><![CDATA[Empfehlungen]]></category> <category><![CDATA[Technologie/IT]]></category> <category><![CDATA[Video]]></category> <guid
isPermaLink="false">http://www.knallisworld.de/blog/?p=1101</guid> <description><![CDATA[Link Der Chuck Norris im JavaScript. Beispiel? I give permission for IBM, its customers, partners, and minions, to use JSLint for evil.]]></description> <content:encoded><![CDATA[<p><a
href="http://developer.yahoo.com/yui/theater/video.php?v=crockford-json">Link</a></p><p>Der Chuck Norris im JavaScript. <img
src='http://www.knallisworld.de/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /></p><p>Beispiel?</p><blockquote><p>I give permission for IBM, its customers, partners, and minions, to use JSLint for evil.</p></blockquote> ]]></content:encoded> <wfw:commentRss>http://www.knallisworld.de/blog/2010/06/06/tipp-douglas-crockford-the-json-saga/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>MacOS X Security</title><link>http://www.knallisworld.de/blog/2010/06/01/macos-x-security/</link> <comments>http://www.knallisworld.de/blog/2010/06/01/macos-x-security/#comments</comments> <pubDate>Mon, 31 May 2010 23:17:36 +0000</pubDate> <dc:creator>knalli</dc:creator> <category><![CDATA[Empfehlungen]]></category> <category><![CDATA[Leseempfehlungen]]></category> <category><![CDATA[MacOS X]]></category> <category><![CDATA[Technologie/IT]]></category> <category><![CDATA[Tipps]]></category> <guid
isPermaLink="false">http://www.knallisworld.de/blog/?p=1083</guid> <description><![CDATA[Boah, was fÃ¼r ein Artikel. Geht zusammengefasst um das Sicherheitskonzept von MacOS X, teilweise im direkten Vergleich zu Windows. Unter anderem auch mit der These: Der geringe Marktanteil von Mac OS X ist nicht Schuld an kaum Malware. Nicht Ã¼beraus technisch Ã¼berladen, also sehr verstÃ¤ndlich (auf deutsch) erklÃ¤rt. Es sind zu viele Informationen auf einmal [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://www.macmark.de/osx_security.php#scheinargument_marktanteil">Boah, was fÃ¼r ein Artikel.</a> Geht zusammengefasst um das Sicherheitskonzept von MacOS X, teilweise im direkten Vergleich zu Windows. Unter anderem auch mit der These: Der geringe Marktanteil von Mac OS X ist nicht Schuld an kaum Malware.</p><p>Nicht Ã¼beraus technisch Ã¼berladen, also sehr verstÃ¤ndlich (auf deutsch) erklÃ¤rt.</p><p>Es sind zu viele Informationen auf einmal gewesen, aber beim ersten Durchlesen sind mir keine Fehler aufgefallen. Einzig allein den Passus, dass &#8220;Mac OS X&#8221; in groÃŸen Teilen offen lÃ¤ge, finde ich unglÃ¼cklich formuliert. Der Autor meinte sicher, dass viele Komponenten (wie das in dem Kontext genannte Samba) offen sind und von Apple dort auch genutzt werden.</p> ]]></content:encoded> <wfw:commentRss>http://www.knallisworld.de/blog/2010/06/01/macos-x-security/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Java Reflection API &#8211; mit Cache, ey!</title><link>http://www.knallisworld.de/blog/2010/04/29/java-reflection-api-mit-cache-ey/</link> <comments>http://www.knallisworld.de/blog/2010/04/29/java-reflection-api-mit-cache-ey/#comments</comments> <pubDate>Wed, 28 Apr 2010 22:03:00 +0000</pubDate> <dc:creator>knalli</dc:creator> <category><![CDATA[Empfehlungen]]></category> <category><![CDATA[Entwicklung]]></category> <category><![CDATA[Java]]></category> <category><![CDATA[Technik]]></category> <guid
isPermaLink="false">http://www.knallisworld.de/blog/?p=1025</guid> <description><![CDATA[EinfÃ¼hrung in Reflection Die Java Reflection API ist Bestandteil des JDK und ermÃ¶glicht den Zugriff auf Methoden, Felder und Annotationen von Klassen und Objekte, also den Instanzen von Klassen. Mit Ausnahme von Annotationen geschieht der Zugriff immer auf einer Meta-Ebene. Mit einem einfachen Beispiel ist diese Meta-Ebene erklÃ¤rt. Stellen wir uns vor, wir wollen ganz [...]]]></description> <content:encoded><![CDATA[<h2>EinfÃ¼hrung in Reflection</h2><p>Die Java Reflection API ist Bestandteil des JDK und ermÃ¶glicht den Zugriff auf Methoden, Felder und Annotationen von Klassen und Objekte, also den Instanzen von Klassen. Mit Ausnahme von Annotationen geschieht der Zugriff immer auf einer Meta-Ebene.</p><p>Mit einem einfachen Beispiel ist diese Meta-Ebene erklÃ¤rt.</p><pre class="brush: java; title: ; notranslate">
class Foo {
private String bar = &quot;private value&quot;;
}
</pre><p>Stellen wir uns vor, wir wollen ganz exemplarisch von dem Objekt foo (<em>foo = new Foo()</em>)den Inhalt von dem Feld bar erhalten. Auf dem Ã¼blichen Weg ist das nicht mÃ¶glich, da das Feld ein privates ist.</p><p>Ãœber den zugehÃ¶rigen Klassentyp (via <em>getClass()</em>) stellt Java eine Reihe von Methoden aus dem Reflection-Paket zur VerfÃ¼gung, u.a. auch <em>Field getDeclaredField(String)</em>. Ein declared field ist ein Instanzattribut eines Objektes, wÃ¤hrend ein field (<em>Field getField(String)</em>) statische Felder finden.</p><pre class="brush: java; title: ; notranslate">
Field field = foo.getClass().getDeclaredField('bar');
</pre><p>Die Variable field enthÃ¤lt aber &#8211; wie man dem Typ entnehmen kann &#8211; aber nicht den Inhalt von bar, sondern ein Field-Objekt. Um an den Inhalt zu kommen, verwendet man die Methode <em>get(Object)</em>. Der Parameter bezeichnet den entsprechenden Kontext, also das Objekt foo von weiter oben.</p><pre class="brush: java; title: ; notranslate">
Object value = field.get(foo);
</pre><p>Das bedeutet im Klartext: Auch fÃ¼r eine weitere Instanz der Klasse Foo (etwa foo2) kann dieses Field fÃ¼r dieses Feld verwendet werden. Es beinhaltet nur die Metainformationen, nicht die eigentlichen Inhalte.</p><p>Dabei ist jedoch zu beachten, dass der SecurityManager aktiv werden kann; in diesem Falle wird eine Exception bei <em>get(Object)</em> geschmissen, weil das Feld nicht sichtbar ist.</p><pre class="brush: java; title: ; notranslate">
field.setAccessible(true);
</pre><p>schafft dabei Abhilfe.</p><h3>Und Methoden?</h3><p>Im Prinzip funktioniert das Schema bei Methoden genauso &#8211; aber bevor ich jetzt einen <a
href="http://de.wikipedia.org/wiki/Radio_Eriwan">Radio Eriwan</a>-Witz loslasseâ€¦</p><p>Im Gegensatz zu den vorherigen Feldern werden Methoden nicht nur Ã¼ber den Namen, sondern auch Ã¼ber die Parametertypen identifiziert (daher kÃ¶nnen Methoden sich vom Namen her in Java auch &#8220;Ã¼berladen&#8221;).</p><pre class="brush: java; title: ; notranslate">
class Bar {
private String name;
String getName() {
return name;
}
String getName(String defaultName) {
return (name == null) ? defaultName : name;
}
}
</pre><p>Die Metainformationen werden entsprechenderweise geladen:</p><pre class="brush: java; title: ; notranslate">
Method method1 = bar.getClass().getDeclaredMethod(&quot;getName&quot;);
Method method2 = bar.getClass().getDeclaredMethod(&quot;getName&quot;, String.class);
</pre><p>SelbstverstÃ¤ndlich ist bei Kenntnisnahme der Klasse auch folgende Zeile gleichwertend:</p><pre class="brush: java; title: ; notranslate">
Method method1 = Bar.class.getDeclaredMethod(&quot;getName&quot;);
</pre><p>Methoden haben im Gegensatz zu Feldern keinen &#8220;Inhalt&#8221;, sondern sind eine AktivitÃ¤t oder Operation &#8212; und zwar auf einem Objekt. Dementsprechend funktioniert das AusfÃ¼hren mittels der Method <em>Object invoke(Object, Object&#8230;args)</em>:</p><pre class="brush: java; title: ; notranslate">
Object result1 = method1.invoke(bar); // getName()
Object result2 = method2.invoke(bar, &quot;default name&quot;); // getName(&quot;defaultName&quot;)
</pre><h3>Und Annotationen?</h3><p>Annotationen sind &#8220;Anmerkungen&#8221; im Quellcode, und seit Java 5 fester Bestandteil des JDKs. Technisch gesehen sind Annotationen besondere Klassen mit eingeschrÃ¤nkten (Java-) MÃ¶glichkeiten, deren Instanz auf einem Meta-Attribut wie Klasse, Feld, Methode oder Methodenparameter &#8220;hÃ¤ngen&#8221;. Mit anderen Worten bedeutet dass, dass man mittels Reflection tatsÃ¤chlich eine Instanz einer Annotation erhÃ¤lt &#8212; allerdings mittels einem Proxy (aus der Java API).</p><pre class="brush: java; title: ; notranslate">
@Entity
class Account {
@Column(name=&quot;id_x&quot;)
private Long id;
}
</pre><p>Die Methode getAnnotation(Class) existiert in allen Typen: Class, Field und Method.</p><pre class="brush: java; title: ; notranslate">
Account account = new Account();
Entity annotation1 = Account.class.getAnnotation(Entity.class).annotationType();
Column annotation2 = Account.class.getDeclaredField(&quot;id&quot;).getAnnotation(Column.class).annotationType();
Assert.assertEquals(&quot;id_x&quot;, annotation2.name());
</pre><h2>Performance</h2><p>Im Regelfall benÃ¶tigt man keinen Zugriff auf Reflection und sollte es vermeiden. Nichtsdestotrotz gestalten sich Konfigurationen, welche auf Basis von Annotationen, meist als sehr einfach, simpel und vor allem Code-konzentriert. Das JPA-Mapping (etwa mit Hilfe von Hibernate) gestaltet sich via Annotationen wesentlich einfacher, schneller und schlanker als mit XML.</p><p><a
href="http://blog.smart-java.nl/blog/index.php/2010/04/25/reflection-slow-well-it-depends/">Jeder Zugriff Ã¼ber die Reflection API kostet Zeit</a>. FÃ¼r Konfigurationen und PlÃ¤ne ist das meist nebensÃ¤chlich; die JPA-Konfiguration wird beim Start der Applikation eingelesen, analysiert und gespeichert. Nebenbei profitiert das natÃ¼rlich von der anfÃ¤nglichen &#8220;Warmup-Phase&#8221;.</p><p>Besteht jedoch ein <em>Access on Demand</em>, so sollte man sich Gedanken um eine geeignete Cachestruktur machen. Wichtig ist dabei, die <span
style="text-decoration: underline;">Metadaten von den eigentlichen Inhalten zu trennen</span>.</p><h2>Cachen &amp; LÃ¶sungsansÃ¤tze</h2><p>Jeder der oben genannten Reflection-Getter gibt es auch jeweils eine getAll-Variante: Class.getDeclaredFields(),Class.getDeclaredMethods(), Class.getAnnotations(), Field.getAnnotations() und Method.getAnnotations().</p><p>Mit einem einfachen Algorithmus kann man die Laufzeit drastisch senken, wenn Objekte des gleichen Typs mittels Reflection untersucht werden.</p><pre class="brush: java; title: ; notranslate">
public class CacheReflectionUtil {
// cache of declared fields of class types
private final Map&lt;Class&lt;?&gt;, Field[]&gt; classDeclaredFields = new HashMap&lt;&gt;();
// Return the declared fields of the given class type.
public Field[] getDeclaredFields(Class&lt;?&gt; type) {
Field[] fields = classDeclaredFields.get(type);
if (fields == null) {
fields = type.getDeclaredFields();
classDeclaredFields.put(type, fields);
ensureAccessibility(fields);
}
return fields;
}
// Ensure that the given fields are accessible.
public void ensureAccessibility(Field[] fields) {
for (Field field : fields) {
// setAccessible will not only set a property but invoke SecurityManager stuff
if (field.isAccessible()) {
field.setAccessible(true);
}
}
}
// Return the declared field of the given class type.
public Field getDeclaredField(Class&lt;?&gt; type, String name) {
for (Field field : getDeclaredFields(type)) {
if (field.getName().equals(name)) {
return field;
}
}
return null;
}
}
</pre><p>Um einen stetigen Speicherverbrauch zu verhindern, empfiehlt sich das Nutzen einer Least-Recently-Used-Struktur. Das Apache-Commons-Paket bietet dies etwa mit der <a
href="http://commons.apache.org/collections/apidocs/org/apache/commons/collections/map/LRUMap.html">LRUMap</a> an.</p> ]]></content:encoded> <wfw:commentRss>http://www.knallisworld.de/blog/2010/04/29/java-reflection-api-mit-cache-ey/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> </channel> </rss>
