Ein Wrappermodul für ein JavaSE Projekt

Für eine NetBeans Rich Client Platform Anwendung ist es ein leichtes eine bestehende .jar-Datei in ein Modul zu kapseln. Das so genannte “Library Wrapper Module” steht im “New Project Wizard” zu Verfügung und man muss nur noch eine (oder mehrere) Java Archive auswählen, fertig. Den Rest erledigt die NetBeans IDE für uns. Das klappt prima, wenn man auch tatsächlich eine .jar-Datei hat, die von extern kommt oder “quasi nie” geändert wird.

Hat man jedoch ein bestehendes Java SE Projekt, welches man jetzt auch für NetBeans nutzen möchte, ist das nicht mehr ganz so einfach. Die manuelle Methode ist bei jeder Änderung im SE-Projekt die erstellte .jar-Datei von Hand in das Wrappermodul zu kopieren, aber ich glaube das will niemand wirklich. Man kann natürlich auch den Pfad der ${dist.jar} anpassen, dass es automatisch in der “release”-Verzeichnis des Moduls kopiert würde. Aber dann wäre das SE-Projekt nicht mehr “eigenständig” und könnte nicht mehr für andere Projekte verwendet werden.

Allerdings kann man sich bei Ant-basierten Projekten recht einfach in den Buildzyklus von NetBeans einklinken. In meinem Wrappermodul für ein (aktives) Java SE Projekt stehen folgende zusätzlichen Zeilen in der build.xml:

1
2
3
4
5
<include file="${suite.dir}/nbproject/wrapped.xml"/>
<target name="compile"
        depends="wrapped.compile,projectized-common.compile"/>
<target name="clean"
        depends="projectized-common.clean,wrapped.clean"/>

Dazu kommt ein Ant-Skript “wrapped.xml” im “nbproject” Verzeichnis der zugehörigen Suite:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?xml version="1.0" encoding="UTF-8"?>
<project name="wrapped" default="compile" basedir=".">
  <target name="-wrapped-init">
    <fail unless="code.name.base.dashes"
     message="Not executed from module project."/>
    <property name="wrapped.path" location="wrapped"/>
    <property name="wrapped.ext" value="lib"/>
    <property name="wrapped.scriptfile"
     location="${wrapped.path}/build.xml"/>
    <property name="wrapped.target.compile" value="jar"/>
    <property name="wrapped.target.clean" value="clean"/>
    <property name="wrapped.jar.dashed"
     value="${code.name.base.dashes}-${wrapped.ext}.jar"/>
    <property name="wrapped.dist.dir"
     location="${basedir}/build"/>
    <property name="wrapped.ext.dir"
     location="${cluster}/modules/ext"/>
  </target>

  <target name="compile" depends="-wrapped-init">
    <ant dir="${wrapped.path}" target="${wrapped.target.compile}"
     inheritall="false" inheritrefs="false"
     antfile="${wrapped.scriptfile}">
      <property name="dist.dir" value="${wrapped.dist.dir}"/>
      <property name="dist.jar"
       value="${wrapped.dist.dir}/${wrapped.jar.dashed}"/>
      <propertyset>
        <propertyref prefix="platforms."/>
      </propertyset>
    </ant>
    <!-- copy "release.files.extra" -->
    <mkdir dir="${wrapped.ext.dir}"/>
    <copy tofile="${wrapped.ext.dir}/${wrapped.jar.dashed}"
    file="${wrapped.dist.dir}/${wrapped.jar.dashed}"/>
  </target>
  <target name="clean" depends="-wrapped-init">
    <ant dir="${wrapped.path}" target="${wrapped.target.clean}"
     inheritall="false" inheritrefs="false"
     antfile="${wrapped.scriptfile}">
      <propertyset>
        <propertyref prefix="platforms."/>
      </propertyset>
    </ant>
  </target>
</project>

Der Rest ist fast wie in einem “normalen” Wrapper Modul. Allerdings erledigt nicht die IDE die Einstellungen für mich, also muss ich sie von Hand im Modul definieren. Aber diese Einstellungen sind relativ wenige und auch nur einmal zu tätigen:

  1. Das JavaSE Projekt muss in ein Unterverzeichnis des Moduls kopiert werden. Ich erledige dies meistens durch einen passenden “svn:externals” Eintrag im Modulverzeichnis.
  2. Die oben genannten Zeilen müssen in die build.xml des Moduls kopiert werden. Am besten hinter die bereits vorhandene <import/> Zeile. Die Zeilen brauchen nicht angepasst werden. Höchstens, wenn die wrapped.xml an einen anderen Ort kopiert wurde.
  3. In der project.xml des Moduls muss die externe Bibliothek noch bekannt gemacht werden. ((Man sollte die .jar nicht über die Projekteinstellungen unter “Wrapped JARs” eintragen, da NetBeans die Datei dann wieder in den “release”-Ordner des Moduls kopiert und damit die automatische Aktualisierung der Bibliothek verhindern würde.)) Dazu müssen folgende Zeilen hinter den <public-packages/> Eintrag eingefügt werden
    <class-path-extension>
      <runtime-relative-path>ext/[wrapped.jar.dashed].jar</runtime-relative-path>
      <binary-origin>build/[wrapped.jar.dashed].jar</binary-origin>
    </class-path-extension>
    <extra-compilation-unit>
      <package-root>[java-se-projekt-verzeichnis]/src</package-root>
      <classpath/>
      <built-to>build/[wrapped.jar.dashed].jar</built-to>
    </extra-compilation-unit>

    Die Variablen in den eckigen Klammern [] muessen durch die entsprechenden Werte ersetzt werden. [wrapped.jar.dashed] entspricht dabei dem Zusammenschluss von “Codebase des Moduls”+”-”+”[wrapped.ext]” mit Bindestrichen statt Punkten zwischen den Paketnamen.

  4. In der project.properties des Moduls müssen mindestens die folgenden beiden Zeilen eingetragen werden:
    wrapped.path=[java-se-projekt-verzeichnis]
    release.files.extra=modules/ext/[wrapped.jar.dashed].jar

    Die eckigen Klammern sind wie oben zu ersetzen. Natürlich kann an dieser Stelle jede andere “wrapped.*”-Variable aus dem “wrapped.xml” Skript ersetzt werden. Somit kann hier auch der Name der gekapselten Bibliothek selber definiert werden. Alle bekannten Variablen stehen im “-wrapped-init” Target des Skripts.

  5. An dieser Stelle muss mindestens einmal ein “build” des Wrappermoduls ausgeführt werden, damit die .jar-Datei der Bibliothek einmal mit dem korrekten Namen an der korrekten Stelle erstellt wird.
  6. Anschließend kann in den Projekteigenschaften des Moduls unter “API Versioning” auch die Liste der “Public Packages” eingestellt werden.

Ab jetzt können die Klassen das JavaSE Projekt wie jede andere Klasse auch innerhalb der NetBeans RCP genutzt werden. Alle Änderungen im JavaSE Projekt werden direkt weiter gereicht ohne das man manuell irgendwelche .jar Dateien irgendwo hin kopieren muss. Und als Bonus erscheint der Quellen-Ordner des JavaSE Projekts auch noch als Quellenordner im Modulprojekt, so dass man sich sogar noch das explizite öffnen des Unterprojekts spart ((Was aber ohne weiteres immer noch möglich ist!)).

Noch ein paar Hinweise zum Schluss:

  • Das eingebundene JavaSE Projekt sollte möglichst eigenständig sein und keine weiteren Abhängigkeiten besitzen. Diese können von diesem Skript nicht korrekt abgebildet werden.
  • Das JavaSE Proejkt muss eine funktionierende build.xml beinhalten. Dazu gehört auch, dass die “build-impl.xml” im “nbproject” Ordner auf den Subversion Server kopiert wurde.
  • Nach dem Ändern der “project.xml” kann es sein, dass die IDE einmal neu gestartet werden muss. Der Quellenordner des Unterprojekts sowie die “genfiles.properties” des Modulprojekts werden von NetBeans manchmal nicht automatisch aktualisiert. Da NetBeans solche Sachen aber in seinem Cache ablegt, ist kann ein Neustart notwendig sein.

Ein Gedanke zu “Ein Wrappermodul für ein JavaSE Projekt

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *


1 × sieben =

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>