Maven-Repository in Eigenregie hosten

Wenn mittels Maven eine Abhängigkeit zur pom.xml-Datei, wie in folgendem Beispiel, hinzugefügt wird:

<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-api</artifactId>
	<version>1.7.26</version>
</dependency>

versucht Maven diese Abhängigkeit von Maven Central, dem zentralen Repository, zu beziehen. Es ist allerdings möglich Abhängigkeiten aus anderen Repositories zu beziehen. Dazu muss der repositories-Block zur pom.xml hinzugefügt werden.

<repositories>
	<repository>
		<id>example</id>
		<url>https://repository.example.org</url>
	</repository>
</repositories>

Aus Nutzersicht ist die Konfiguration von Maven damit erledigt. Soll ein solches Maven-Reposity aufgesetzt werden, ist dies relativ einfach möglich. Dazu wird ein Verzeichnis per HTTP über den Webserver Nginx ausgeliefert. Innerhalb dieses Verzeichnisses wird ein gesicherter Ordner erstellt, welcher über WebDAV erreicht werden kann. Die entsprechende Nginx-Konfiguration sieht für diesen Fall wie folgt aus:

server {
        listen   443 ssl;
        listen [::]:443 ssl;

        ssl_certificate /etc/letsencrypt/live/repository.example.org/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/repository.example.org/privkey.pem;

        root /var/www/example/repository;

        server_name repository.example.org;

        location / {
                autoindex     on;
        }

        location /upload {
                dav_methods     PUT DELETE MKCOL COPY MOVE;
                dav_ext_methods   PROPFIND OPTIONS;

                dav_access    user:rw group:rw all:rw;

                create_full_put_path  on;

                autoindex     on;

                auth_basic "restricted";
                auth_basic_user_file /var/www/example/repository/upload/.htpasswd;
        }
}

Die .htpasswd-Datei, welche für die Authentifizierung benötigt wird, kann mit dem Tool htpasswd erstellt werden:

htpasswd -c .htpasswd nutzer1

Bei der Nutzung wird das gewünschte Passwort erfragt. Soll ein weiterer Nutzer hinzugefügt werden, so muss der Parameter -c entfernt werden:

htpasswd .htpasswd nutzer2

Anschließend wird die Konfiguration von Nginx mittels:

service nginx reload

aktualisiert. Danach kann WebDAV für die Ressource verwendet werden. In der pom.xml-Datei für das Projekt, welches ein Artefakt für das Repository erzeugt, wird der build-Bereich erweitert und der distributionManagment-Bereich hinzugefügt:

            </plugin>
        </plugins>
        <extensions>
            <extension>
                <groupId>org.apache.maven.wagon</groupId>
                <artifactId>wagon-webdav-jackrabbit</artifactId>
                <version>3.2.0</version>
            </extension>
        </extensions>
    </build>
    <distributionManagement>
        <repository>
            <id>example</id>
            <url>dav:https://repository.example.org/upload/</url>
            <layout>default</layout>
        </repository>
    </distributionManagement>
</project>

Im Extension-Bereich wird das Wagon-Plugin für WebDAV aktiviert. Dieses sorgt dafür das die Artefakte per WebDAV zum Repository hochgeladen werden. In dem distributionManagment-Bereich wird die WebDAV-URL definiert. Wenn nun ein:

mvn deploy

durchgeführt wird, wird dies allerdings nicht funktionieren. Hintergrund ist das der upload-Ordner per Basic authentication geschützt ist. Die Zugangsdaten für diese Authentifikation müssen noch hinterlegt werden. Natürlich werden diese nicht in der pom.xml hinterlegt, da dies aus Gründen der Sicherheit keine gute Idee wäre. Stattdessen werden die Daten in der settings.xml hinterlegt. Diese befindet sich im Pfad:

~/.m2/settings.xml

In dieser Datei wird eine server-Sektion mit den Zugangsdaten hinzugefügt:

<settings>
	<servers>
		<server>
			<id>example</id>
			<username>example</username>
			<password>password</password>
		</server>
	</servers>
</settings>

Anschließend kann das Artefakt erfolgreich mittels:

mvn deploy

in das Repository hochgeladen werden. Problematisch ist das sich die Daten nur im upload-Verzeichnis und nicht im eigentlichen Verzeichnis des Repository liegen. Zur Lösung hierfür wird ein Cronjob, im Kontext des Nutzers www-data, angelegt:

sudo -u www-data crontab -e

Ziel des Cronjobs ist es die Daten aus dem upload-Verzeichnis regelmäßig in das eigentliche Verzeichnis des Repository zu kopieren:

*/5  *    * * *   cp /var/www/example/repository/upload/* /var/www/example/repository/ -r

Damit wird alle 5 Minuten der Inhalt des uploadVerzeichnisses in das Repository kopiert. Ein Verschieben kann leider nicht durchgeführt werden, da die Metadaten beim jeden Deployment von Maven eingelesen werden und erweitert werden. Hier könnten Optimierungen durchgeführt werden, so das alle Dateien bis auf die Metadaten verschoben werden. Soll ein nicht öffentliches Repository erstellt werden, kann auf den zusätzlichen upload-Ordner verzeichnet werden und das Hauptverzeichnis selber per WebDAV befüllt werden. So lange die Zugangsdaten für den Server in der settings.xml-Datei hinterlegt sind, können seitens Maven die entsprechenden Artefakte bezogen werden.

WebDAV unter Nginx einrichten

Der freie Webserver Nginx beherrscht nicht nur das gewöhnliche Ausliefern von Daten über HTTP und HTTPS, sondern verfügt daneben über weitere Module. Mit einem dieser Module kann WebDAV für eine Ressource bereitgestellt werden. Dazu muss die Konfiguration der jeweiligen Seite unter /etc/nginx/sites-available/ angepasst werden. In diesem Beispiel wäre dies:

nano /etc/nginx/sites-available/example

Zur dieser Konfigurationsdatei wird folgende Konfiguration hinzugefügt:

server {
        listen   443 ssl;
        listen [::]:443 ssl;

        ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem;

        root /var/www/example;

        server_name example.org;

        location / {
                dav_methods     PUT DELETE MKCOL COPY MOVE;
                dav_ext_methods   PROPFIND OPTIONS;
                dav_access    user:rw group:rw all:rw;

                autoindex     on;
        }
}

In diesem Fall wird für die Domain example.org die WebDAV-Unterstützung aktiviert. Dateien können hierbei ohne weitere Authentifizierung herunter- und hochgeladen werden. Soll WebDAV abgesichert werden, so geschieht das über den Basic authentication. Dazu wird dem location-Part folgendes hinzugefügt:

auth_basic "restricted";
auth_basic_user_file /var/www/example/.htpasswd;

Die .htpasswd-Datei kann mit dem Tool htpasswd erstellt werden:

htpasswd -c .htpasswd nutzer1

Bei der Nutzung wird das gewünschte Passwort erfragt. Soll ein weiterer Nutzer hinzugefügt werden, so muss der Parameter -c entfernt werden:

htpasswd .htpasswd nutzer2

Anschließend wird die Konfiguration von Nginx mittels:

service nginx reload

aktualisiert. Danach kann WebDAV für die Ressource verwendet werden.

Klassenname für Logger unter Java ermitteln

Wenn ein Logger unter Java erstellt wird, so wird diesem in den meisten Fällen ein Name übergeben, über den er später identifiziert und konfiguriert werden kann. Mit der Simple Logging Facade for Java kurz SLF4J würde das Ganze so aussehen:

Logger logger = LoggerFactory.getLogger("Testclass");

Die erste Möglichkeit wäre es nun den Namen der Klasse, über die Klasseninformationen mittels:

Logger logger = LoggerFactory.getLogger(Testclass.class.getName());

zu ermitteln. Alternativ kann diese Klasseninformation direkt in die Methode gegeben werden:

Logger logger = LoggerFactory.getLogger(Testclass.class);

Alle diese Methoden haben den Nachteil das die jeweilige Klasse in irgendeiner Form übergeben werden muss. Wenn nun dieser Logger in eine andere Klasse kopiert wird um ihn dort ebenfalls zu nutzen muss der Name der Klasse angepasst werden. Anders funktioniert das Ganze mit der folgenden Methode:

Logger logger = LoggerFactory.getLogger(new Exception().fillInStackTrace().getStackTrace()[0].getClassName());

Bei diesem Beispiel wird eine neue Exception instanziiert und aus dem Stacktrace dieser Exception der Name der Klasse ermittelt. Somit kann diese Zeile von Klasse zu Klasse kopiert werden, ohne das eine Anpassung notwendig wird.

Regionsspezifische Zeichen unter Java ermitteln

Auf der Welt existieren eine Reihe von Konventionen rund um das Thema Formatierung von Zahlen und anderen Werten. So existieren z.B. unterschiedlichste Reglungen für Dezimaltrennzeichen. Unter Java lassen sich diese dank der entsprechenden Unterstützung problemlos einbinden. So können Werte anhand der Locale, welche eine definierte Region repräsentiert, einfach formatiert werden:

double value = 42.2324;
String format = "#.00";

DecimalFormat decimalFormat = new DecimalFormat(format, DecimalFormatSymbols.getInstance(Locale.GERMANY));
String formattedString = decimalFormat.format(value);

System.out.println(formattedString);

In diesem Beispiel wird der Wert 42.2324 anhand der Locale und einer Formatierung in den Wert 42,23 konvertiert. Manchmal ist es allerdings notwendig Informationen über die einzelnen Trennzeichen und ähnliches zu erlangen. Auch diese Informationen können unter Java ermittelt werden:

Locale locale = new Locale("en", "GB");
DecimalFormat format = (DecimalFormat) DecimalFormat.getInstance(locale);

char decimalSeparator = format.getDecimalFormatSymbols().getDecimalSeparator();
char groupingSeparator = format.getDecimalFormatSymbols().getGroupingSeparator();
Currency currency = format.getDecimalFormatSymbols().getCurrency();

Hier wird eine Locale angelegt und mit dieser eine Instanz der Klasse DecimalFormat erzeugt. Anschließend kann diese Instanz genutzt werden, um die regionsspezifischen Zeichen wie z.B. den Dezimalseparator zu ermitteln.

Freier Java-Decompiler

In jeder besseren Entwicklungsumgebung für Java ist ein Decompiler integriert. Daneben existieren auch Standalone-Decompiler wie der Java Decompiler. Der Decompiler ermöglicht es den Quelltext aus dem Kompilat wieder herzustellen. Dies funktioniert bei Java relativ gut, da dort der Quelltext nur in Bytecode für die JVM umgewandelt wird. Dieser Bytecode ist noch relativ High-Level, so das die Rückumwandlung einfacher vonstattengeht. Neben dem Standalone-GUI, existieren Plugins für Eclipse und IntelliJ IDEA.

Die grafische Oberfläche des Decompiler

Zu finden ist das Projekt unter java-decompiler.github.io, der entsprechenden Quelltext befindet sich ebenfalls auf GitHub. Lizenziert ist der Decompiler unter der GPL in der Version 3 und damit freie Software.