# Maven, ausführbare jar-Datei unter spziellen Bedingungen - welche Plug-ins?



## dermoritz (10. Jan 2011)

Ich glaube so langsam stoße ich an die Grenzen der "Konventionen" von Maven und muss mich an die "Konfiguration" machen. Alles in allem sind meine Anforderungen aber gar nicht so exotisch nur weiß ich nicht in welcher Kombination man welche Plug-Ins mit welcher Konfiguration verwenden soll. Ich hoffe ihr könnt mir helfen.

Zunächst: Was will ich am Ende haben?:
Ein ausführbare jar-Datei möglichst inklusive aller Abhängigkeiten. 

Warum "jar-with-dependencies" (Assembly plugin) nicht reicht:
Problem 1: unter den "Abhängigkeiten" befindet sich eine dll-Datei (jNotify), deren Pfad muss in den "java library path" eingetragen werden (kann der Überhaupt innerhalb der jar datei liegen?)
Derzeitige Lösung: ohne Maven die Datei manuell in den Ordner der jar-Datei kopieren und die jar-Datei in diesem Pfad ausführen. Eine Lösung mit Maven wäre super.

Problem 2: mehrere Abhängigkeiten benutzen identisch benannte properties-Dateien mit verschiedenem Inhalt. Das Assembly-Plugin speichert nur eine dieser Dateien - das funktioniert natürlich nicht.
Derzeitige Lösung: shade-Plugin - es hängt diese Properties-Dateien einfach aneinander. Eine schlechte Lösung sobald auch bestimmte Properties identisch sind, aber mit verschiedenen Werten vorkommen (z.B. log4j.properties). Das "one-jar-plugin" hab ich auch probiert - es funktioniert nicht (die jar-Dateien werden zwar als ganzes kopiert, jedoch ihre Inhalte nicht korrekt aufgelöst) - gibt es für dieses (gängige?) Problem eine "Standard"-Lösung?

Problem 3: bestimmte Resourcen (z.B. eigen properties Dateien) sollen nicht in der jar-Datei landen sondern zusammen mit der jar-Datei abgelegt und wenn möglich gezippt werden. Dies macht man ja eigentlich mit dem Assembly Plug-in oder? Nur verwende ich es im Moment nicht, da es wie beschrieben Probleme macht. Ich verwende das shade-plugin zusammen mit dem jar-plugin.

Und genau bei Problem 3 bin ich stutzig geworden, ob ich mir nicht mal grundsätzlich Gedanken über die richtige Verwendung der Plug-ins machen sollte und da dachte ich ihr könnt mir helfen.


----------



## bygones (10. Jan 2011)

ich bin immer noch der Meinung man sollte nich für alles was nur geht Maven versuchen zu nutzen / umbzubiegen.

Maven hilft mir äußerst effektiv beim automatischen Build und releasen eines Projekts/artifakts.

Das Deployen eines Produkts (also das Projekt plus alle Konfigurationen, mögliche Startskripte, Wrapper oder was auch immer was), würde ich nicht bzw mache ich nicht mit maven.


----------



## dermoritz (10. Jan 2011)

Danke dieser Ansatz ist ja der den ich gerade Verfolge er löst aber leider nur das 3. Problem und eventuell das 1. Wobei diese mit dem Assembly-Plugin leicht zu lösen wären oder?

Mein Hauptproblem ist aber das 2.: ich bekomme im Moment nur sehr unschön eine lauffähige jar-Datei. Und vielleicht gibt es im Moment schon Konflikte innerhalb der zusammengesetzten Properties-Datei von denen ich noch nichts weiß.


----------



## kama (10. Jan 2011)

Hallo,



dermoritz hat gesagt.:


> Zunächst: Was will ich am Ende haben?:
> Ein ausführbare jar-Datei möglichst inklusive aller Abhängigkeiten.


Ich greife hier mal etwas vor...
Ist das ein muss oder ginge es auch so:

ein ZIP-Datei deren Inhalt etwas so aussieht:

```
ZIP-Datei
  +-- DLL Ordner mit DLL Datei
  +-- etc Ordner mit property Dateien
  +-- lib Ordner mit Abhängigkeiten (.jar)
  +-- bin Ordner mit Ausführungsscript (Unix/windows)
```
Wäre das auch eine Möglichkeit?



dermoritz hat gesagt.:


> Warum "jar-with-dependencies" (Assembly plugin) nicht reicht:
> Problem 1: unter den "Abhängigkeiten" befindet sich eine dll-Datei (jNotify), deren Pfad muss in den "java library path" eingetragen werden (kann der Überhaupt innerhalb der jar datei liegen?)


Geht so wie ich das Verstanden habe nicht, da das ja eine VM-Argument ist -Djava.library.path=n:\anwendungXX)...



dermoritz hat gesagt.:


> Derzeitige Lösung: ohne Maven die Datei manuell in den Ordner der jar-Datei kopieren und die jar-Datei in diesem Pfad ausführen.


Wer soll das machen? Du möchtest die Anwendung doch auslieferen und dann einfach nur auspacken und starten können oder?



dermoritz hat gesagt.:


> Problem 2: mehrere Abhängigkeiten benutzen identisch benannte properties-Dateien mit verschiedenem Inhalt. Das Assembly-Plugin speichert nur eine dieser Dateien - das funktioniert natürlich nicht.
> Derzeitige Lösung: shade-Plugin - es hängt diese Properties-Dateien einfach aneinander. Eine schlechte Lösung sobald auch bestimmte Properties identisch sind, aber mit verschiedenen Werten vorkommen (z.B. log4j.properties). Das "one-jar-plugin" hab ich auch probiert - es funktioniert nicht (die jar-Dateien werden zwar als ganzes kopiert, jedoch ihre Inhalte nicht korrekt aufgelöst) - gibt es für dieses (gängige?) Problem eine "Standard"-Lösung?


Sorry aber unterschiedliche Dateinamen der Properties files...das wäre die Lösung ? ;-)



dermoritz hat gesagt.:


> Problem 3: bestimmte Resourcen (z.B. eigen properties Dateien) sollen nicht in der jar-Datei landen sondern zusammen mit der jar-Datei abgelegt und wenn möglich gezippt werden. Dies macht man ja eigentlich mit dem Assembly Plug-in oder? Nur verwende ich es im Moment nicht, da es wie beschrieben Probleme macht. Ich verwende das shade-plugin zusammen mit dem jar-plugin.


...? maven-assembly-plugin ist genau dafür aber eben unterschiedliche Dateinamen ...und nicht gleicher Dateiname mit unterschiedlicher Inhalt...

Gruß
Karl Heinz Marbaise


----------



## dermoritz (11. Jan 2011)

hallo und Danke kama

"...Wäre das auch eine Möglichkeit?" ja das wäre es! Wie geht das mit Maven? (Damit wäre mein Problem 2 wahrscheinlich gelöst?!)
Denn mit unterschiedlichen Namen der Properties-Dateien kann ich es nicht lösen - es handelt sich um extern eingebundene Bibliotheken (EMF standalone). Aber wie man bei "onejar" nachlesen kann ist das ein häufiges Problem z.b. für log4j.properties - die heißt ja in sehr vielen jars genau so.
(Also wenn alle jars im lib Ordner landen - wunderbar, wenn alle in der jar wären - perfekt.)

"Wer soll das machen? Du möchtest die Anwendung doch auslieferen und dann einfach nur auspacken und starten können oder?" - wenn maven mir eine entsprechende zip-datei ausspucken könnte wäre es perfekt


----------



## kama (11. Jan 2011)

Hallo,



dermoritz hat gesagt.:


> "...Wäre das auch eine Möglichkeit?" ja das wäre es! Wie geht das mit Maven? (Damit wäre mein Problem 2 wahrscheinlich gelöst?!)


Ich habe ein Projekt auf github da kannst Du dir solch einen Prozess anschauen wie der geht...Das Module supose-cli benutzt das maven-appassembler-plugin, damit kannst Du eine Batch/Shell Datei erzeugen lassen, die auch eine -Dlibrary.path=... bekommt. Du kannst in der POM (<extraJvmArgument>-Dxyz=$BASEDIR/dll</extraJvmArgument>) nutzen um das Problem mit der DLL zu lösen...

Am Ende kommt im supose-cli ein tar.gz/zip file raus, dass man einfach Auspackt und per shell-script oder batch-datei startet. In diesem Falle eine Kommandozeilen Anwendung ....
Die Struktur in dem tar.gz/zip ist bis auf den DLL Ordner schon so vorhanden...

```
ZIP-Datei
  +-- etc Ordner mit property Dateien
  +-- lib Ordner mit Abhängigkeiten (.jar)
  +-- bin Ordner mit Ausführungsscript (Unix/windows
```

Du kannst Dir das Teil ja mal anschauen....wenn Du fragen hast einfach melden.

Gruß
Karl Heinz Marbaise


----------



## dermoritz (11. Jan 2011)

Vielen Dank!

...bin am untersuchen und melde mich...


----------



## dermoritz (11. Jan 2011)

leider funktioniert die supose-web-Seite nicht. Ich hab Probleme das commons-cli2 Artefakt zu finden. Könntest du mir nen Link besorgen?


----------



## kama (11. Jan 2011)

Hallo,



dermoritz hat gesagt.:


> leider funktioniert die supose-web-Seite nicht. Ich hab Probleme das commons-cli2 Artefakt zu finden. Könntest du mir nen Link besorgen?


Sorry Datenbank war down...gefixed...

Hier findest Du das Artefakt:
SupoSE - Requirement - Redmine

Das Artefakt tausche ich gerade aus...damit ich das los werde...;-(

Gruß
Karl Heinz Marbaise.


----------



## dermoritz (11. Jan 2011)

kann es sein das m2eclipse mit der Projektstruktur Probleme hat? Ein riesiges rotes Ausrufezeichen prangt am supose-filters-Projekt. Eclipse scheint mit der 2fach verschachtelten Struktur Probleme zu haben?!
In der Konsole funzt alles einwandfrei...


----------



## kama (11. Jan 2011)

Hallo,



dermoritz hat gesagt.:


> kann es sein das m2eclipse mit der Projektstruktur Probleme hat? Ein riesiges rotes Ausrufezeichen prangt am supose-filters-Projekt. Eclipse scheint mit der 2fach verschachtelten Struktur Probleme zu haben?!
> In der Konsole funzt alles einwandfrei...


Abgesehen von der Struktur die M2 Eclipse bzw. Eclipse platt Klopft...

Das bedeutet nur, dass Du nach dem Import noch mal alle Project selectieren musst und dann rechte maustaste -> "Maven" -> "Update project configuration" ....dann sollte alles Ok sein....
Liegt an den Goals die von M2 Eclipse während eines Imports ausgeführt werden kann man ändern wenn man möchte...

Windows -> Preferences -> Maven -> goals to run on project import (üblicherweise leer). Hier müsste man dann proccess-resources eintragen...oder eben obige Vorgehensweise.

Gruß
Karl Heinz Marbaise


----------



## dermoritz (11. Jan 2011)

DANKE,

für die Erklärung für m2Eclipse und

den Rest! Es funktioniert! und alles das was ich gerade von dir gelernt habe wollte ich die ganze Zeit lernen -> was hat es mit "assembly descriptors" auf sich 

Im Moment hab ich nur noch ein Frage zur entstandenen .bat Datei bzw. zum Resourcehandling:

Im Moment hab ich meine properties unter conf abgelegt und greife auf sie per

```
InputStream propsIn = ImageUebergabeMain.class.getResourceAsStream(PROPERTIES_FILENAME);
```
zu. Das hat bei "jar-with-dependencies" immer funktioniert.
Nun funktioniert das nicht mehr. Die Properties Datei wird nun immer relativ zum aktuellen Pfad gesucht. wenn man die bat Datei in bin startet wäre das ../conf oder? Nun würde ich aber ungern diese Projekt/Assembly -spezifische Eigenschaft im code verankern (also mein getResourceAsStream anpassen).
Ich hab das Gefühl, dass es etwas mit <includeConfigurationDirectoryInClasspath>true</includeConfigurationDirectoryInClasspath> zu tun hat? Oder wie füge ich mein /conf Verzeichnis dem classpath hinzu? Dann müsste es ja gehen oder?


----------



## kama (11. Jan 2011)

Hallo,



dermoritz hat gesagt.:


> den Rest! Es funktioniert!


Cool....also auch das mit der DLL laden ?



dermoritz hat gesagt.:


> und alles das was ich gerade von dir gelernt habe wollte ich die ganze Zeit lernen -> was hat es mit "assembly descriptors" auf sich


Ein Descriptor ist eine Art "Macro" für eine Liste von Dateien und/oder Verzeichnissen...Der Assembly Descriptor bin-component.xml enthält alles was gebraucht wird...Das wird aber sowohl für Windows als auch für Unix gebraucht somit schreibe und Pflege ich diese Liste eben nur einmal während in bin.xml bzw. bin-unix.xml eben die Batch Datei bzw. das Shell Script angezogen wird...wg. Windows/Unix.



dermoritz hat gesagt.:


> Im Moment hab ich meine properties unter conf abgelegt und greife auf sie per
> 
> ```
> InputStream propsIn = ImageUebergabeMain.class.getResourceAsStream(PROPERTIES_FILENAME);
> ...


ja genau per includeConfigurationDirectoryInClasspath....Wenn ich die Batch Datei noch richtig im Kopf habe steht der Eintrag für die configuration an erster Stelle (nicht ganz sondern an Zweiter)...somit wird immer im conf Verzeichniss zuerst gesucht...

Gruß
Karl Heinz Marbaise


----------



## dermoritz (11. Jan 2011)

Das Problem ist nicht das conf-Verzeichnis sondern die "relation". das conf verzeichnis wird bei mir nur gefunden wenn ich im root Verzeichniss des Programms bin. sobald ich die bat anklicke wird die properties-Datei in bin/konf/ gesucht oder eben in <aktuellerpfad>/konf. Wie krieg ich es hin das es in <root verzeichnis>/konf gesucht wird?


Mir ist auch aufgefallen, dass die properties datei auch in der jar-Datei landet - was muss ich machen dass sie da verschwindet?


----------



## kama (11. Jan 2011)

Hi,



dermoritz hat gesagt.:


> Das Problem ist nicht das conf-Verzeichnis sondern die "relation". das conf verzeichnis wird bei mir nur gefunden wenn ich im root Verzeichniss des Programms bin. sobald ich die bat anklicke wird die properties-Datei in bin/konf/ gesucht oder eben in <aktuellerpfad>/konf. Wie krieg ich es hin das es in <root verzeichnis>/konf gesucht wird?


Bin gerade verwirrt...

Das conf Verzeichniss ist im classpath...Hast Du mal die Ausführung in eines Dos-Box probiert ? Oder hast Du nur problem mit der Ausführung per Click ?

Ich weiß leider nicht wie Windows (Welches XP, Windows 7, ?) eine BAT ausführt wenn man drauf klickt...Macht eventuell auch noch einen Unterschied ob die Datei .bat oder .cmd heißt ? 



dermoritz hat gesagt.:


> Mir ist auch aufgefallen, dass die properties datei auch in der jar-Datei landet - was muss ich machen dass sie da verschwindet?


Tja das einfachste ist Du legst die Datei in einen anderen Pfad anstatt in src/main/resources (habe ich auch gemacht autsch stimmt ja garnicht) oder Du musst dafür dann exclude regeln anlegen...

Gruß
Karl Heinz Marbaise


----------



## dermoritz (12. Jan 2011)

Also die Properties-Datei wird nur gefunden wenn ich im Root der Anwendung bin und die bat-datei von dort starte. Denn von dort ist die properties-Datei in ./conf/ zu finden.
Sobald ich aus einem anderen Verzeichnis starte wird versucht die properties-Datei relativ zu diesem Verzeichnis zu finden. Wenn man eine bat-Datei doppelklickt ist das aktuelle Verzeichnis das der .bar-Datei - dann wird versucht die properties in bin/conf/ zu finden.
Also irgendwas stimmt noch nicht mit der Konfiguration der properties-Datei insgesamt gibts meiner Meinung nach 3 Stellen an denen man schauen könnte:
1. Component-descriptor:

```
<fileSet>
            <directory>src/main/resources</directory>
            <outputDirectory>conf</outputDirectory>
            <includes>
                <include>ImageUebergabe.properties</include>
            </includes>
        </fileSet>
```
(wenn ich hier nen exlude machen würde würde es weder im Verzeichnis noch in der jar-landen oder?)


2. Da frage ich mich woher weiß der appassembler was mein Configuration directory ist? Muss das einen speziellen Namen haben?

```
<includeConfigurationDirectoryInClasspath>true</includeConfigurationDirectoryInClasspath>
```

3. der Aufruf der Resource. Die ewige Frage muss vorne noch ein "/" dran? (im Moment funktioniert beides nicht)

```
InputStream propsIn = ImageUebergabeMain.class.getResourceAsStream(PROPERTIES_FILENAME);
```

Und übrigens: Ja das mit der dll funktioniert, aber so:

```
<extraJvmArguments>-Djava.library.path=./lib</extraJvmArguments>
```


----------



## mvitz (12. Jan 2011)

Wie sieht den aktuell deine .bat aus? Solltest du dort noch den Classpath zusammenbauen, dann kann das auftreten. Wenn du den Classpath in der JAR aufbaust (Manifest), dann füge den Root Ordner relativ zu dieser JAR hinzu.


----------



## dermoritz (12. Jan 2011)

im Moment wird der classpath über die bat-Datei gesetzt. Die Frage wäre eben an welcher Stelle ich was konfigurieren muss, dass am Ende im classpath das richtige steht.
manuell hinzufügen ist keine Option, die bat Datei wird generiert und danach will ich die nicht mehr anfassen.

Das es geht zeigt kamas "Supose" dort ist der erste Eintrag des classpath %basedir%/etc bei mir müsste da %basedir%/conf stehen. Die Frage ist eben warum es da nicht drinne steht oder umgekehr was muss man machen damit es da drinne steht. Entweder reichen die 3 stellen aus meinem vorherigen Post nicht oder ich hab etwas falsch gemacht?!

Edit: ich habe gerade bemerkt, dass bei mir der erste Eintrag im classpath auch %basedir%/etc ist! Nun lasse ich die properties-Datei nach etc kopieren und nun geht es!
Die Frage wäre wo und wie kann man den etc-ORdner umbenennen?

Nun ist mir auch aufgefallen, dass das einbinden der DLL nicht mehr funktioniert - da habe ich das selbe Problem (das Problem mit der properties hat es nur verdeckt): jva-librarypath="./lib" stimmt nur falls ich im root-Pfad der Anwendung bin und da war ich immer, da sonst die Propertiesdatei nichtgeladen werden konnte.

nun hab ich es auf "../lib" geändert - nun funktioniert es solange man die bat-Datei durch doppelklick startet. Letztendlich bräuchte ich aber <pfadderBatDatei>/../lib oder? Wie kann ich den Pfad der bat-Datei referenzieren?


----------



## dermoritz (12. Jan 2011)

Hab mal etwas rumgeforscht und konnte alle meine restliche Fragen und Probleme klären:

Appassembler :: Maven Plug-In - appassembler:assemble

dort findet man z.B. "...default=etc" und damit ist das Problem mit der properties Datei vom Tisch.

Das Problem mit der dll hab ich nun zumindest Windowsspezifisch gelöst:

```
<extraJvmArguments>-Djava.library.path="%~dp0\..\lib"</extraJvmArguments>
```
damit ist immer die Relation zum Pfad der bat-Datei(%~dp0) hergestellt - die einzige Relation die man hat. So kann man die bat-Datei durch doppelklick oder aus der Konsole aus einem beliebigen Verzeichnis aufrufen .

zum Schluss nochmal Danke an alle und insbesondere Danke an Kama!!

(einer eleganten Lösung mit einer einzigen ausführbaren jar-Datei + properties-Datei bin ich aber nach wie vor nicht abgeneigt ;-))


----------



## kama (12. Jan 2011)

Hallo,


dermoritz hat gesagt.:


> ```
> <extraJvmArguments>-Djava.library.path="%~dp0\..\lib"</extraJvmArguments>
> ```


Du solltest es so machen:

```
<extraJvmArguments>-Djava.library.path=%BASEDIR%/lib"</extraJvmArguments>
```
 Dann sollte dann auch funktionieren in diesem Falle für Windows...$BASEDIR wäre die Variante für Unix.

Wenn Du für beide Plattformen erzeugen musst, dann eben zweimal einen execution block machen wo dann einmal $BASEDIR bzw. %BASEDIR% angegeben ist...

Gruß
Karl Heinz Marbaise


----------



## dermoritz (13. Jan 2011)

danke - da hätte ich eigentlich selbst draufkomen können. Ich hatte ja "%basedir%" schon das ein oder andere mal erwähnt ;-).


----------

