Rouven: Pfad der eigenen Klasse feststellen oder rel. Pfad finden

Hallo,

das da oben ist der zugegeben schlechte Versuch eine angemessenen Titel für das Problem zu finden. Die Sache ist folgende: Ich habe einige Java-Klassen die auf verschiedene XML-Konfigurationsdateien zugreifen sollen. In meiner Entwicklungsumgebung (und in der späteren Anwendungsumgebung) sollen diese relativ zur Klasse im Unterordner config liegen.
Bsp.: AgentController benötigt Zugriff auf config/ac.xml
Nun ist aber beim Instanziieren der Klasse das "aktuelle Verzeichnis" nicht unbedingt das in dem die Klasse liegt (z.B. wenn die Klasse von einer anderen Anwendung instanziiert wird). Ergebnis: Ich finde meine Konfigurationsdatei nicht mehr wieder.
Ich habe versucht mit per System.getProperty("user.dir") das aktuelle Verzeichnis geben zu lassen, nur leider ist das das Verzeichnis in dem der java-Befehl abgesetzt wurde o.ä..
Hat jemand eine Idee wie ich die Datei wiederfinde?

Nehme jeden Tipp...

Danke!

MfG
Rouven

--
-------------------
ss:) zu:) ls:& fo:) de:< va:{ ch:? sh:) n4:( rl:? br:$ js:| ie:) fl:(
  1. abend,

    das da oben ist der zugegeben schlechte Versuch eine angemessenen Titel für
    das Problem zu finden. Die Sache ist folgende: Ich habe einige Java-Klassen
    die auf verschiedene XML-Konfigurationsdateien zugreifen sollen. In meiner
    Entwicklungsumgebung (und in der späteren Anwendungsumgebung) sollen diese
    relativ zur Klasse im Unterordner config liegen.

    ich verstehe dich/das nicht so ganz. hier herrscht doch eine feste struktur
    hinsichtlich der datei-/package-hierarchie. egal von wo deine klassen
    instanziiert werden, kannst du doch unabhängig davon das package der
    jeweiligen klasse ermitteln. zu diesem packagenamen packst du einfach ein
    '.config' dran und somit sollte der zugriff auf die XML-dateien eiegentlich
    gewährleistet sein !?

    mfg,
    (tanz das)
    Z.N.S.

    --
    <img src="http://www.comunicout.com/zebulon/en.gif" border="0" alt="">
    .:LIFE ON OTHER PLANETS IS DIFFICULT:.
    1. Hallo,

      ich verstehe dich/das nicht so ganz. hier herrscht doch eine feste struktur
      hinsichtlich der datei-/package-hierarchie. egal von wo deine klassen
      instanziiert werden, kannst du doch unabhängig davon das package der
      jeweiligen klasse ermitteln.

      Wie?
      (Und wie definierst du "Package"? Und was hast du gewonnen, wenn du das
      Package kennst?)

      Gruß
      Slyh

      1. abend,

        mist, hab mir selber geantwortet ;(
        siehe [pref:t=86578&m=512506]

        mfg,
        (tanz das)
        Z.N.S.

        --
        <img src="http://www.comunicout.com/zebulon/en.gif" border="0" alt="">
        .:LIFE ON OTHER PLANETS IS DIFFICULT:.
    2. abend,

      ok. nach deinem posting [pref:t=86578&m=512498] verstand ich die problematik ;)

      mfg,
      (tanz das)
      Z.N.S.

      --
      <img src="http://www.comunicout.com/zebulon/en.gif" border="0" alt="">
      .:LIFE ON OTHER PLANETS IS DIFFICULT:.
  2. Hi,

    das da oben ist der zugegeben schlechte Versuch eine angemessenen Titel für das Problem zu finden. Die Sache ist folgende: Ich habe einige Java-Klassen die auf verschiedene XML-Konfigurationsdateien zugreifen sollen. In meiner Entwicklungsumgebung (und in der späteren Anwendungsumgebung) sollen diese relativ zur Klasse im Unterordner config liegen.
    Nun ist aber beim Instanziieren der Klasse das "aktuelle Verzeichnis" nicht unbedingt das in dem die Klasse liegt (z.B. wenn die Klasse von einer anderen Anwendung instanziiert wird). Ergebnis: Ich finde meine Konfigurationsdatei nicht mehr wieder.
    Ich habe versucht mit per System.getProperty("user.dir") das aktuelle Verzeichnis geben zu lassen, nur leider ist das das Verzeichnis in dem der java-Befehl abgesetzt wurde o.ä..
    Hat jemand eine Idee wie ich die Datei wiederfinde?

    Wenn ich mich richtig erinnere, dürfte Class.getResource oder Class.getResourceAsStream geeignet sein.

    Es ist ja nicht gesagt, daß die Klasse aus einem normalen Verzeichnis geladen wurde - sie kann ja irgendwoher aus dem CLASSPATH kommen, also auch aus einem Jar-File - demzufolge muß auch dieser gesamte CLASSPATH durchsucht werden ...

    cu,
    Andreas

    --
    MudGuard? Siehe http://www.Mud-Guard.de/
    Fachfragen per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
  3. Hallo,

    das da oben ist der zugegeben schlechte Versuch eine angemessenen Titel für das Problem zu finden. Die Sache ist folgende: Ich habe einige Java-Klassen die auf verschiedene XML-Konfigurationsdateien zugreifen sollen. In meiner Entwicklungsumgebung (und in der späteren Anwendungsumgebung) sollen diese relativ zur Klasse im Unterordner config liegen.

    Eine interessante Problematik, vor der übrigens nicht nur Java-Programme
    stehen, sondern eigentlich jedes Programm, das in irgend einer Form
    auf Dateien in seinem "eigenen Verzeichnis" zugreifen muß.

    Das Problem ist, daß dieses "eigene Verzeichnis" eigentlich nur
    theoretisch existiert. Wie du ja selbst schon festgestellt hast, ist
    das aktuelle Arbeitsverzeichnis nicht zwingend auch das Verzeichnis,
    in dem sich die ausführbare Programmdatei befindet.

    Unter Windows läßt sich beispielweise für jede Verknüpfung festlegen,
    in welchem Verzeichnis die dort referenzierte Datei ausgeführt werden
    soll. (Siehe das Textfeld "Ausführen in:" bei den Verknüpfungs-
    Eigenschaften.)

    Prinzipiell bestehen wohl 4 Möglichkeiten, mit dieser Problematik
    umzugehen:

    1.) Man geht davon aus, daß das Arbeitsverzeichnis stets auch das
    Verzeichnis ist, in dem sich die Programmdatei befindet. Alle Datei-
    Operationen führt man daher relativ zum aktuellen (Arbeits-)Verzeichnis
    durch.
    Wie wir festgestellt haben, muß das Arbeitsverzeichnis nicht mit dem
    Programm-Verzeichnis übereinstimmen, somit handelt es sich hierbei
    um die schlechteste Vorgehensweise.

    2.) Man legt die Konfigurationsdateien an eine zentrale Stelle im
    System ab, die unabhängig vom Programm-Verzeichnis immer absolut
    erreichbar ist. Im Falle von Linux wäre dies bspw. das Home-Verzeichnis
    des aktuellen Benutzers. Im Falle von Windows wohl soetwas wie
    "c:\Dokumente und Einstellungen\Ich".
    Damit ist sichergestellt, daß die Daten immer auffindbar sind.
    Nachteil: Bei einer Konfigurationsdatei mag sowas noch funktionieren.
    Wenn allerdings mehrere oder größere Dateien zugreifbar sein sollen,
    ist ein Umkopieren in das Home-Verzeichnis wohl kaum wirklich hilfreich.

    3.) Ablage _einer_ Konfigurationsdatei an der genannten zentralen
    Stelle. In dieser Konfigurationsdatei ist u.a. angegeben, wo sich das
    Programmverzeichnis und damit die anderen Dateien, die für die
    Programmausführung benötigt werden, befinden.
    Unter Windows könnte zur Ablage auch die Registry verwendet werden.

    Nachteil: Ein einfaches Verschieben der Programmdateien ist nach der
    Installation nicht mehr möglich, da die Pfade "fest" in der Konfigurations-
    Datei abgelegt sind. (Natürlich könnte man die entsprechenden
    Einträge in der Konfigurations-Datei oder der Registry einfach
    von Hand korrigieren.)

    Diese 3. Möglichkeit wird übrigens von der meisten Windows-Programmen
    realisiert. Üblicherweise legen Windows-Programme ihre gesamte
    Konfiguration in der Registry ab, und verweisen von dort auf das
    Programmverzeichnis. Da auf die Registry global zugegriffen werden
    kann, kann das Programm stets ermitteln, wo es installiert ist.

    (Ein Nachteil der Registry von Windows ist sicherlich, daß diese bei
    einer Neuinstallation von Windows üblicherweise nicht gesichert wird
    bzw. werden kann, und daher alle Programme neu installiert und
    konfiguriert werden müssen.)

    Seit JDK 1.4 bietet Java zur globalen Ablage von Konfigurationsdaten
    übrigens das Package java.util.prefs, und im speziellen die Klasse
    java.util.prefs.Preferences an.

    Aus dem JavaDoc der Klasse "Preferences":
    "A node in a hierarchical collection of preference data. This class
    allows applications to store and retrieve user and system preference
    and configuration data. This data is stored persistently in an
    implementation-dependent backing store. Typical implementations
    include flat files, OS-specific registries, directory servers and SQL
    databases. The user of this class needn't be concerned with details
    of the backing store."

    Es lassen sich also plattformunabhängig hierarchisch Konfigurations-
    Daten ablegen. Zur Speicherung wird ein plattformspezifische Ablageort
    gewählt. Unter Windows ist dies meines Wissens die Registry. Da die
    Ablage aber für den Programmierer völlig transparent erfolgt, hat
    das eigentlich gar nicht zu interessieren.

    (Ich selbst habe ich die Preferences-Klasse noch nie verwendet, so daß
    ich keine weitere Aussage bzgl. des Für und Wider treffen kann.)

    Es gibt noch eine weitere Möglichkeit zum Auffinden von Dateien des
    Programms:

    4.) Java bietet die Möglichkeit Dateien, die sich irgendwo im aktuellen
    Classpath befinden, aufzufinden. Da sich die Programmdatei des
    Hauptprogramms üblicherweise im Classpath befindet -- auch wenn dies
    nicht immer der Fall sein muß -- lassen sich alle Dateien, die sich
    im selben oder einem der untergeordneten Verzeichnisse zum
    Hauptprogramm befinden, auf diese Weise auffinden und laden.

    Java bietet die Methode java.lang.Class.getResource() an, die eine
    Datei durch den ClassLoader, der die Klasse des Class-Objekts, auf das
    die Methode aufgerufen wird, auffinden läßt.
    Üblicherweise hat dieser ClassLoader mindestens das Verzeichnis, in
    dem sich die genannte Hauptprogramm-Klasse befindet, in seinem
    Classpath.

    Beispiel:

    class MyMainProgram
    {
        public MyMainProgram()
        {
            // Tu was...
            // [...]

    URL myConfigFile = getClass().getResource("/config/general.cfg");

    // Lade die Daten aus "general.cfg".
            // [...]
        }
    }

    Was passiert hier?
    Die Methode "getClass()", die in jedem Objekt existiert, liefert das
    Class-Objekt der Klasse. (Genauer gesagt das Class-Objekt zur Klasse,
    in deren Instanz wir uns gerade befinden.)
    Diese Klasse sei das Hauptprogramm.

    Der Klasse ist intern der ClassLoader zugeordnet, der die Klasse
    geladen hat. Dieser ClassLoader hat den Pfad der Klasse in seinem
    Classpath. Alle Aufrufe von "getResource()" auf das Class-Objekt werden an diesen ClassLoader gegegeben. Dieser wiederum versucht die
    genannte Datei in seinem Classpath zu finden, und liefert im
    Erfolgsfall ein URL-Objekt mit einer Referenz auf eben diese Datei
    zurück.
    Die Datei selbst muß dabei nicht einmal zwingend in einem Verzeichnis
    liegen, das im Classpath ist. Wie im Beispiel zu sehen ist, reicht
    es, daß sich das Verzeichnis "config" in einem Verzeichnis befindet,
    das sich im Classpath befindet.

    Um wieder auf das Ausgangsproblem zurückzukommen:
    Die Konfigurationsdateien lassen sich über die Methode "getResource()"
    finden und dann laden, sofern sich die Klasse des Hauptprogramms im
    Classpath befindet. (Das ist üblicherweise nur dann nicht der Fall,
    wenn die Klasse z.B. über einen eigenen ClassLoader oder den
    URLClassLoader "manuell" anhand eines Dateinamens nachgeladen wurde.)

    Nachteil: Wenn sich im aktuellen Classpath sehr viele Verzeichnisse
    (oder auch JAR-Dateien) befinden, ist es durchaus möglich, daß sich
    in mehreren dieser Verzeichnisse bspw. eine Datei "general.cfg"
    befindet -- evtl. sogar in Kombination mit dem Verzeichnis "config",
    somit also "/config/general.cfg" mehrmals im Classpath vorkommt.

    Mir ist nicht bekannt, auf welche Weise Java (bzw. der ClassLoader)
    diesen Konflikt auflöst. Ich vermute, daß einfach die Datei genommen
    wird, die in dem Verzeichnis liegt, das weiter vorne im Classpath
    steht. (Man kann damit allgemein sagen, daß das Verhalten bei
    Doppeldeutigkeiten des Dateinamens undefiniert ist, da man den
    Classpath evtl. selbst gar nicht kontrollieren kann.)

    Umgehen kann man dieses Problem sicherlich durch die Vergabe von
    eindeutigen Verzeichnis- oder Dateinamen, z.B. durch Voranstellen des
    Package-Namens ("/de-slyh-mycoolapp-config/general.cfg") oder
    dergleichen.

    Natürlich läßt sich die letztbeschriebene Möglichkeit des Findens von
    Dateien auf dem Classpath mit der Ablage des Programmverzeichnisses
    in einer Konfigurationsdatei kombinieren. Hierzu legt man die
    Konfigurationsdatei (mit einem möglichst eindeutigen Namen) in dasselbe
    Verzeichnis ab, in dem sich auch die Programmdatei des Hauptprogramms
    befindet, so daß sie vom ClassLoader gefunden werden kann. In die
    Konfigurationsdatei speichert man den Programmpfad ab.

    Im Hauptprogramm ruft man dann einfach beim Programmstart die Methode
    "getResource()" des ClassLoaders auf, läßt sich die Konfigurations-
    Datei ermitteln, und liest aus dieser den Programmpfad aus.
    Alle nachfolgenden Dateioperationen läßt man dann nicht mehr über
    denn ClassLoader abwickeln, sondern verwendet den Absolutpfad aus
    der Konfigurations-Datei.
    Grund: Da der ClassLoader beim Aufruf von "getResource()" immer den
    gesamten Classpath nach der gewünschten Datei absuchen muß, wäre bei
    vielen zu suchenden Dateien die Performanz ganz sicher nicht die beste...

    Gruß
    Slyh

    1. Hallo Slyh,

      wie auch immer hilfreich es sich herausstellt, VIELEN DANK für dieses extrem ausführliche Posting. Die Sache mit getResource führe ich mir mal zu Gemüte. Wegen der Performance: Da kann man ja wie du schon geschrieben hast sicherlich anfangen zu tricksen, eine Datei suchen, von dieser Datei dann den Ort der restlichen ableiten, das passt schon irgendwie.
      Das Problem rührt daher, dass wir im Moment eine leicht heikle Sache machen: Wir schreiben ein Testframework für "beliebige" Java-Anwendungen. Mittels Bytecode-Injizierung werden einzelne Aufrufe unserer Software in ein fertiges Programm gestreut und die Frage ist nun wie finden unsere Klassen ihre Umgebung wieder, das user.dir wird ja irgendwas von der eigentlich ausgeführten Anwendung sein.
      Aber ich denke das wird sich schon irgendwie finden lassen, vielen Dank nochmal!

      MfG
      Rouven

      --
      -------------------
      ss:) zu:) ls:& fo:) de:< va:{ ch:? sh:) n4:( rl:? br:$ js:| ie:) fl:(
      1. Hi,

        wie auch immer hilfreich es sich herausstellt, VIELEN DANK für dieses extrem ausführliche Posting. Die Sache mit getResource führe ich mir mal zu Gemüte. Wegen der Performance: Da kann man ja wie du schon geschrieben hast sicherlich anfangen zu tricksen, eine Datei suchen, von dieser Datei dann den Ort der restlichen ableiten, das passt schon irgendwie.

        Aber wie schon gesagt darauf achten, daß es sich nicht (mehr) um eine Datei im Filesystem handeln muß - wenn das ganze als Jar im CLASSPATH liegt. Das ist bei Java ja durchaus üblich.

        cu,
        Andreas

        --
        MudGuard? Siehe http://www.Mud-Guard.de/
        Fachfragen per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
        1. Hallo,

          ja, das Problem wird aber wohl nicht bestehen, es geht hier explizit um einzelne xml-Dateien die dort von Hand abgelegt werden.

          MfG
          Rouven

          --
          -------------------
          ss:) zu:) ls:& fo:) de:< va:{ ch:? sh:) n4:( rl:? br:$ js:| ie:) fl:(
        2. Hallo,

          Aber wie schon gesagt darauf achten, daß es sich nicht (mehr) um eine Datei im Filesystem handeln muß - wenn das ganze als Jar im CLASSPATH liegt. Das ist bei Java ja durchaus üblich.

          Ja, das stimmt prinzipiell schon, da dann (evtl.) nur die JAR-Datei im
          Classpath steht, nicht aber das Verzeichnis, in dem sich die JAR-Datei
          befindet.

          Andererseits hat man in einem solchen Fall dann bei Konfigurations-
          dateien ohnehin nur die Möglichkeit, die Datei an einer zentralen
          Stelle abzulegen, da sich die JAR-Datei nachträglich nicht mehr
          (sinnvoll) ändern läßt.

          Natürlich läßt sich (etwas komplizierter) aber auch der Pfad der
          JAR-Datei ermitteln, in der sich eine Ressource befindet.
          Man muß letztendlich nur überprüfen, ob es sich beim Protokoll der
          zurückgegebenen URL um "jar" handelt. In diesem Fall schneidet man die
          ersten 4 Zeichen ("jar:") und alles ab dem Ausrufezeichen ("!") der
          URL ab, und erhält damit die URL zur JAR-Datei.

          Eine JAR-URL sieht z.B. so aus:
            jar:file:/c:/mein/pfad/meinJar.jar!/pfad/dateiImJar.cfg

          Daraus wird:
            file:/c:/mein/pfad/meinJar.jar

          Damit hat man jetzt zum einen den Pfad zur JAR-Datei, kann zum anderen
          aber auch einzelne Dateien selektiv aus der JAR-Datei laden, indem
          man den Pfad der gewünschten Datei nach dem Ausrufezeichen wieder
          anhängt.
          (Natürlich ist dann -- wie gesagt -- nur lesender Zugriff sinnvoll.)

          Gruß
          Slyh