Eine Jar (OJDBC) nachträglich in die Ziel-Jar integrieren

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.

Da jedoch das Projekt im Form des Sourcecodes „für alle“ 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.

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.

Die wichtigen Teile sind: Das Ant-Jar-Command muss den Zusatz „update“ 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’s.

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

<?xml version="1.0" encoding="UTF-8"?>
<project name="visualDependencies" default="help" basedir="../../../">
	<!-- The path of the actual artifact (project name), without the file suffix. -->
	<property name="project.name" value="visualDependencies.one-jar" />
	<!-- The path of the ojdbc driver, without the file suffix. -->
	<property name="ojdbc.name" value="ojdbc14" />
	<!-- DO NOT CHANGE THIS LINES UNLESS YOU KNOW WHAT YOU DO! -->
	<property name="project.jar" value="${project.name}.jar" />
	<property name="ojdbc.jar" value="${ojdbc.name}.jar" />
	<!-- Set actual paths of artifacts. -->
	<property name="application.path" location="${basedir}/target/${project.jar}" />
	<property name="ojdbc.parent.path" location="${basedir}/oracle" />
	<property name="ojdbc.path" location="${ojdbc.parent.path}/lib/${ojdbc.jar}" />
	<!-- Shows help (default target) -->
	<target name="help">
		<echo message="See http://www.knallisworld.de/blog/2010/11/23/eine-jar-ojdbc-nachtraglich-in-die-ziel-jar-integrieren/" />
		<echo message="Usage: attachOJDBC" />
	</target>
	<!-- Checks if the artifacts are available. Throws exceptions if they not exist. -->
	<target name="checkDependencies">
		<available file="${application.path}" property="application.exists" />
		<available file="${ojdbc.path}" property="ojdbc.exists" />
		<fail unless="application.exists" message="The application file (${application.path}) does not exist." />
		<fail unless="ojdbc.exists" message="The ojdbc file (${ojdbc.path}) does not exist." />
	</target>
	<!-- Integrates all files of ojdbc.parent.path into the target jar. -->
	<target name="attachOJDBC" depends="checkDependencies">
		<jar update="true" destfile="${application.path}">
			<fileset dir="${ojdbc.parent.path}" />
		</jar>
	</target>
</project>

SenchaCon

Sagte ich letztens, Sencha würde sich gut entwickeln? Die hauseigene SenchaConference ist gestartet, und die Firma hat erstmal kräftig auf den Putz gehauen. Es gibt nicht nur die finale Version SenchaTouch (quasi das ExtJS für mobile Plattformen inkl. UI), sondern direkt ein passendes Ext Designer Update zum entwickeln von Touch Anwendungen. Und auch einen Marktplatz für Entwickler/Kunden — den so genannten SenchaDev-Bereich. Ob der was taugen wird, das wird man später sehen.

Im Einzelnen: Ausgewählte Informationen per Copy-Paste aus dem @tdgi-Staccato:

  1. #SenchaCon ext designer to be moved to CSS, icon, template, theme and event mangers!
  2. #SenchaCon Web services: font, data image resizing and more, all from #senchainc.
  3. #SenchaCon #ExtJS 4has a brand new layout engine. Same API.
  4. #SenchaCon #ExtJS 4 has 4000 unit tests!
  5. #SenchaCon #ExtJS 4 is UI tested by a new tool called VisualQA. Awesome!
  6. #SenchaCon #ExtJS 4 most useful documentation ever. All classes documented.
  7. #SenchaCon #ExtJS 4 examples integrated into docs.
  8. #SenchaCon #ExtJS 4 upgrade guide available!
  9. #SenchaCon #ExtJS 4 API improvements, clears cruft. Standardizing naming, funcs conventions.
  10. #SenchaCon #ExtJS 4 new charting package. Bye bye flash!
  11. #SenchaCon #ExtJS 4: building complex forms are a lot easier!
  12. #SenchaCon #ExtJS 4: Record becomes Model. More complex data manipulation now possible.
  13. #SenchaCon #ExtJS 4: data associations are now going to empower a new level of application development!
  14. #SenchaCon #ExtJS 4: local and session storage APIs available.
  15. #SenchaCon Sencha Command is a way to start your apps.
  16. #SenchaCon #ExtJS 4: sencha command is automated by the model generator.
  17. #SenchaCon JSBuilder is tied into Sencha Command.
  18. #SenchaCon #ExtJS 4: that was beta in six weeks. Final is feb 28, 2011
  19. #SenchaCon #ExtJS 4: VisualQA will be open to end debs, release date unknown. Bye bye selenium, hellos new world of testing RIAs!

Eine neue Layoutengine hatte man bereits im Vorfeld leicht angekündigt; die Model-Neuerfindung ist auch nicht überraschend, da es bereits in SenchaTouch Einzug fand. Model Associations sind genial. Der Wegfall von Flash im Charting-Paket sollte auch nicht verwundern, schließlich hat man jetzt bereits zwei alternative Know-Hows in Form von Frameworks eingekauft.

Alles in allem hört sich das alles super an: Mehr UI-Testing ist speziell in einer RIA sehr schwierig und könnte durch geeignetes Framework-Hilfstool sicherlich um einiges besser machbar werden. Was sich genau hinter Sencha Command verbirgt bzw. welche Power es genau hat, wird man sehen.

Sencha [Update]

Es ist noch nicht so lange her, da schlossen sich die Firmen bzw. Entwickler von Ext JS, Raphaël und jQTouch zusammen und bildeten die Firma Sencha Inc. bzw. die Sencha Labs Foundation. Ext JS entwickelt ein gleichnamiges RIA-JavaScript-Framework sowie eine eigene Schnittstelle zu GWT (Ext GWT), während Raphaël ein JavaScript-Framework ist, welches mit generiertem SVG (auch IE-kompatibel) Charts und Graphen erzeugt. Mit Hilfe des jQTouch-Framework kann man Webanwendungen bauen, die nahezu wie native iPhone-Apps aussehen und sich auch ähnlich bedienen lassen.

Seitdem hat sich vieles getan: Sencha hat SenchTouch vorgestellt, welches aktuell als RC auf Version 1.0 zusteuert. Ähnlich wie jQTouch lässt sich mit diesem RIA-ähnlichen-JavaScript-Framework (stark verwandter Unterbau wie Ext JS) eine Applikation für mobile Endgeräte (typischerweise iPads und iPhones) bauen — inklusive mit den entsprechenden speziellen, optimierten UI-Elementen. Außerdem gibt es den Ext Designer: eine eigene grafische Oberfläche zum Entwickeln von Ext JS Komponenten. Super praktisch, und im professionellen Einsatz sicher sein Geld wert.

Dazugekommen sind außerdem:

  • Connect: ein node.js basierter Applicationserver
  • JavaScript InfoVis Toolkit: Ein JavaScript-Framework zur Darstellung von Graphen, etwa Bäumen oder anderer Strukturdiagramme.
  • CSS3PIE: macht neue CSS3-Attribute auch für die IE6-8 über JavaScript verfügbar.
  • Sencha Animator (Beta): Animationen erstellen mit Ausgabemodus „HTML5+CSS3“
  • RemoteJS: macht das (Remote-)Debuggen „on device“ für Android-Entwickler einfacher

… und wahrscheinlich noch ein paar schöne Dinge. Wie etwa eine eigene Messe nächste Woche, die SenchaCon. Leider ist die San Francisco. 🙁

Der Sencha Verbund entwickelt sich so langsam zu einer richtig guten Sache, die auch schön viel in die Community bringt.

Update (01.12.2010): tinySrc ist jetzt auch dabei.

Links

{DEVELOPERS SHAME DAY}

Cem hat kürzlich den Developers Shame Day ins Leben gerufen.

Als Stichtag würde ich den 3.11.2010 vorschlagen. Ich stelle mir vor, dass an diesem Tag alle Entwickler, die ein Blog oder eine Seite betreiben, ein kleines Stück Code präsentieren, dass aus heutiger (oder vielleicht auch damaliger) Sicht total hirnverbrannt ist. Ein Stück Code, dass uns selbst die Schamröte ins Gesicht steigen lässt. Dabei ist egal, ob es sich um PHP, JavaScript, CSS, HTML, Java, C oder sonst etwas handelt. Es muss nur von euch sein und es darf nicht verändert werden (umeventuell doch als total verrückter Hund dazustehen ). Ein kleiner erläuternder Text sollte natürlich auch nicht fehlen.

Und das ist mein Beitrag, wohl einer meiner ersten Gehversuche in PHP. Der Quellcode entstammt einer Datei namens „functions.inc.php“ [sic!]. Und es scheint so ;), also wäre es eine größere Anwendung gewesen, ich habe jedoch echt keine Ahnung mehr welche — vielleicht die erste PHP-Homepage in Eigenentwicklung? Die Datei hatte sich irgendwie auf meine „Informatik-Diskette“ [sic!] (Oberstufenkurs) verirrt, von der ich tatsächlich noch ein Abbild hatte. Der Rest der Programmiersünden muss entweder (m)einen Backup-Aufräumaktionen oder einem vor einigen Jahren aufgetreten Backupmediumfehler zum Opfen gefallen sein. Zu meiner Verteidigung kann ich wohl nur sagen hoffen, dass dies einer erste Spielversion war und nie „produktiv“ wurde.

Listing

Bitte in voller Länge genießen. Jede Zeile ist ein Genuss. *ankoppfass*

Unverändert, nur Benutzername/Passwort habe ich ausgeixt.

Datei: functions.inc.php (von 2002 oder 2003)

<?php
//conf.inc.php
//please don't change this file manually - go to your admin-area to change settings!!!
$listname="Meine Linkliste";
$listname2="Downloads";
$linkwidth="100%";
$addpagewidth="50%";
$catorder="name";
$incatsort="Hits";
$perpage="5";
$max_search="10";
$adminpw="a";
$max_desc_leng="500";
$html="ON";
$language="german.lang";
$timeformat="1";
 @include("global/$language"); // language-file
 @include("../global/$language"); // language-file
//connect.inc.php
// DON'T CHANGE THIS FILE MANUALLY - EDIT ONLY VIA ADMIN-AREA
$server="localhost";
$user="xxx";
$pass="xxx";
$mydb="xxx";
$db_prefix="xl_";
$db_prefix2="dl_";
function JPDiv ($a,$b) {
  $i=0;
  $j=0;
  while($j==0) {
    if(($a/($b*($i+1)))>1) {
      $i++;
    } else {
      $j = 1;
    }
  }
return $i;
}
function JPDatumZeit ($a) {
  $JPTag = array("Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag");
  $JPMonat = array("Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember");
  $JPDatumTag = $JPTag[date("w",$a)];
  $JPDatumMonat = $JPMonat[date("n",$a)-1];
  $JPDatumJahr = date("Y",$a);
  $JPZeit = date("H:i:s",$a);
  $b = $JPDatumTag . ", " . date("j") . ". " . $JPDatumMonat . " " . $JPDatumJahr . " [" . $JPZeit . "]";
return $b;
}
function JPDatumZeit2 ($a) {
  $JPDatumJahr = date("Y",$a);
  $JPZeit = date("H:i:s",$a);
  $b = date("j") . "." . date("w",$a)+1 . "." . $JPDatumJahr . " [" . $JPZeit . "]";
return $b;
}
class my_zugriff{
//Variablen für Zugangsdaten
var $user="xxx";		//Benutzername für den MySQL-Zugang
var $password="xxx";		//Passwort
var $host="localhost";	//Name (IP-Adr.) des Rechners mit MySQL
var $dbname="xxx"; 	//Name der Datenbank
//Weitere Variablen
var $db_verbindung=false; //Speichert die Verbindungskennung
var $sql_result=false; //Speichert die Kennung eines ausgewerteten SQL-Befehls
//Konstruktor definieren
function my_zugriff(){
   //Funktion verbinden wird bei Aufruf der Klasse ausgeführt
	 $this->verbinden();
}
//Falls keine Verbindung besteht,
//Verbindung aufbauen und Datenbank als Standard definieren
function verbinden(){
if ($this->db_verbindung==false){
   $this->db_verbindung = @mysql_connect($this->host, $this->user, $this->password);
   if(empty($this->db_verbindung)){
      $this->fehler("Beim Verbinden");
   }
   $auswahl = @mysql_select_db($this->dbname, $this->db_verbindung);
   if(empty ($auswahl)){
      $this->fehler("Beim Ausw&auml;hlen der DB");
   }
   return $this->db_verbindung;
}
}
//Gibt Fehlermeldung aus und beendet das Skript
function fehler($fehlerpunkt){
    echo $fehlerpunkt . " ist ein Fehler aufgetreten!<br>";
		echo mysql_error() . "<br>"; //Fehlerbezeichnung
		echo mysql_errno();	 	 		//Fehlernummer
		echo "</body></html>";		//Html-Tags schließen
		exit;
}
//SQL-Befehl ausführen
function sql_befehl($sql){
$this->sql_result = @mysql_query($sql, $this->db_verbindung);
if (empty($this->sql_result)){
	 $this->fehler("Beim Senden der Abfrage");
}
return $this->sql_result;
}
//Falls zuvor ein SQL-Befehl ausgeführt wurde,
//wird hier das Array mit den Datensätzen ausgegeben
function sql_daten(){
if(!empty($this->sql_result)){
		$sql_array=@mysql_fetch_array($this->sql_result);
		return $sql_array;
}else{
		$this->fehler("Beim Ausgeben der Datens&auml;tze");
}
}
//eig. Fkt
function sql_num_rows($sql){
$this->sql_befehl($sql);
$rows = MYSQL_NUM_ROWS($this->sql_result);
return $rows;
}
}
$db=new my_zugriff();
$db->sql_befehl("SELECT elem_string FROM elem_global WHERE elem_name='JPmyVersion'");
$myVersion_now = $db->sql_daten();
 $JPmyVersion = $myVersion_now[0];
?>

Selbstreflexion

  • Struktur: globale Variablen
  • Struktur/Aufbau: als Script noch okay, aber als Include? Oweh..
  • Includes mittendrin
  • Variabel- und Funktionsnamen multilingual
  • Inhalt der Funktionen..
  • kein gängiger Codestyle (ja, der Blog zeigt’s richtig an)
  • Inline-SQL(!)

Kurzum: What the hell…?

Weitere via Google oder Twitter oder Facebook.

„Die Rente ist sicher.“

Nein, es geht nicht um die Rente. Sondern um den neuen Personalausweis.

Da hat die FAZ ein äußerst aufschlussreiches Interview mit der sog. IT-Beauftragten der Bundesregierung geführt. Ich formuliere es mal so: Aus Sicht der Komik hat es eine gute Note verdient.

Dazu ein lustiges Zwischen-den-Zeilen-lesen (Mirror, weil fefe den Server kaputt gemacht hat).