Nginx unter macOS mittels Homebrew installieren und nutzen

Nginx wird für gewöhnlich unter Linux genutzt. Für Entwicklungszwecke kann es interessant sein Nginx unter macOS zu betreiben. Zur Installation von Nginx wird Homebrew benötigt. Homebrew ist ein Paketmanager für macOS, mit welchem viele Open-Source-Projekte unter macOS installiert werden können. Ist Homebrew installiert kann Nginx auf dem Terminal mittels:

brew install nginx

installiert werden. Standardmäßig läuft Nginx bei der Installation über Homebrew auf dem Port 8080. Hintergrund ist das der Webserver somit ohne root-Rechte bzw. ohne sudo genutzt werden kann. Wird der Port auf 80 oder generell auf einen Port kleiner 1024 gestellt, werden wieder entsprechende administrative Rechte benötigt. Soll der verwendete Port geändert werden, muss die Konfigurationsdatei angepasst werden:

nano /usr/local/etc/nginx/nginx.conf

In dieser findet sich folgender Block:

server {
  listen       8080;
  server_name  localhost;

Dort kann anschließend der Port geändert werden. Neben dem Port kann dort die Default-Location geändert werden. Dazu wird der server-Block bzw. dessen Unterblock, der location-Block angepasst:

location / {
  root /Users/seeseekey/Web;
  autoindex on;

Die root-Direktive gibt den Pfad an, welcher über den Webserver ausgeliefert wird. Die Option autoindex sorgt für das entsprechende Directory-Listing, was für Entwicklungszwecke nützlich sein kann. Gestartet und gestoppt werden kann der Service mittels:

brew services start nginx

bzw.

brew services stop nginx

Natürlich kann dies mittels restart in einem Rutsch erledigt werden:

brew services restart nginx

Anschließend kann Nginx mit der veränderten Konfiguration genutzt werden.

JavaScript-Bibliothek für interaktive Karten

Interaktive Karten im Browser darzustellen ist sicherlich kein seltener Anwendungsfall im Web. Für die eigentliche Darstellung der Karten existieren unterschiedlichste Frameworks bzw. Bibliotheken wie z.B. OpenLayers.

Eine mit Leaflet realisierte Kartenapplikation

Daneben existiert seit 2011 die JavaScript-Bibliothek Leaflet. Mit dieser leichtgewichtigen Bibliothek, können interaktive Karten schnell aufgesetzt werde. Dabei werden TileMaps ebenso wie Web Map Services als Quelle für die eigentliche Karte unterstützt. Neben Features wie Overlays und der Unterstützung unterschiedlicher Projektionen ist Leaflet für die Nutzung auf dem Desktop und auf mobilen Endgeräten ausgelegt.

Der Quelltext der Bibliothek ist auf GitHub zu finden. Lizenziert ist Leaflet unter der BSD-Lizenz in der Zwei-Klausel-Variante und damit freie Software. Die offizielle Seite des Projektes ist unter leafletjs.com zu finden.

Java Exceptions in Strings verpacken

Wenn in einem Java-Programm etwas schiefläuft so, wird in den meisten Fällen eine Exception erzeugt und diese nach oben im Stack durchgereicht, bis sie behandelt wird. Manchmal ist es notwendig die Exception bzw. Teile davon in einen String umzuwandeln. Natürlich kann die Exception nun mühsam von Hand auseinander genommen und in einen String konvertiert werden. Sinnvoller ist es die Hilfsmethoden aus der Utility-Bibliothek Guava zu nutzen:

String stacktrace = Throwables.getStackTraceAsString(e);

Bei der Methode getStackTraceAsString wird der Stacktrace der betreffenden Exception in einen String umgewandelt. Neben dieser Methode existieren weitere Methoden rund um das Exception-Handling in der Klasse Throwables. Einfacher wird das Ganze, wenn ein Logger genutzt wird und in diesem die Exception auftauchen soll:

Logger logger = LoggerFactory.getLogger(new Exception().fillInStackTrace().getStackTrace()[0].getClassName());
logger.error("Exception: ", e);

In diesem Fall bieten die meisten Logger die Möglichkeit an, das Throwable direkt als Parameter zu übergeben. Die weitere Verarbeitung der Exception wird anschließend vom Logger erledigt.

Konvertierungen zwischen alter und neuer Datums- und Zeit-API

Seit Java 8 verfügt die Programmiersprache über eine sinnvolle Datums- und Zeit-API. In den meisten Fällen kann diese API ohne weitere Probleme genutzt werden. Problematisch wird es nur, wenn die neue API im Zusammenhang mit Legacy-Code genutzt werden soll. Meist wird dort die Klasse Date aus dem Package java.util genutzt. Damit werden Methoden benötigt, um eine Brücke von der alten zur neuen API und umgekehrt zu schlagen. Um ein Date in eine LocalDateTime umzuwandeln, kann folgende Methode genutzt werden:

public static LocalDateTime convertToLocalDateTime(Date date) {
    return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
}

Soll der Wert, welcher in der LocalDateTime gespeichert ist, wieder in ein Date-Objekt konvertiert werden, kann folgende Methode genutzt werden:

public static Date convertToDate(LocalDateTime localDateTime) {
    return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
}

Bei diesen Konvertierungsmethoden ist zu beachten, dass die Zeitzonen bei der Konvertierung ignoriert werden. Stattdessen wird die Konvertierung mit der Standardzeitzone des Systems durchgeführt. Für die Konvertierung unter Berücksichtigung und Speicherung der Zeitzonen kann die Klasse ZonedDateTime genutzt werden. Die entsprechenden Methoden zur Konvertierung wären folgende:

public static ZonedDateTime convertToZonedDateTime(Date date, ZoneId zoneId) {
    return date.toInstant().atZone(zoneId);
}

public static Date convertToDate(ZonedDateTime zonedDateTime) {
    return Date.from(zonedDateTime.toInstant());
}

Bei der Konvertierung einer Date-Instanz in eine ZoneDateTime muss die entsprechende Zeitzone als ZoneId mitgegeben werden.

Probleme mit der Methode appendReplacement unter Java

Mit regulären Expressionen kann in einem String nach bestimmten Zeichenketten gesucht werden. Daneben ist es natürlich auch möglich diese Zeichenketten zu modifizieren und sie anschließend zu ersetzen. Unter Java würde das Ganze wie folgt aussehen:

private static String convertBlockquotes(String html) {

	Pattern patternBlockquote = Pattern.compile("<blockquote>(.+?)</blockquote>", Pattern.DOTALL);

	// Find all blockquote tags
	final Matcher matcher = patternBlockquote.matcher(html);
	StringBuffer stringBuffer = new StringBuffer(html.length());

	// Translate each tag
	while (matcher.find()) {

		// Get complete tag
		String group = matcher.group();

		// Remove tags
		group = group.replace("<blockquote>", "");
		group = group.replace("</blockquote>", "");

		// Replace old tag with markdown equivalent
		matcher.appendReplacement(stringBuffer, group);
	}

	matcher.appendTail(stringBuffer);
	return stringBuffer.toString();
}

Wenn nun in dem gefundenen String sich z.B. ein $-Zeichen (das Zeichen für Ersetzung im Kontext der Matcher-Klasse) befindet, wird spätestens bei der Zeile:

// Replace old tag with markdown equivalent
matcher.appendReplacement(stringBuffer, group);

ein Problem auftreten, welches sich in einer IllegalArgumentException äußert:

Exception in thread „main“ java.lang.IllegalArgumentException: Illegal group reference

Hintergrund ist das bestimmte Zeichen wie $ oder der Backslash maskiert werden müssen. Dies konnte manuell erledigt werden, bevor die Methode appendReplacement aufgerufen wird:

group = group.replace("$", "\\$");

Einfach ist es die integrierte Methode quoteReplacement zu nutzen:

group = Matcher.quoteReplacement(group);

Diese maskiert die entsprechenden Zeichen. Ein etwas andere Lösung ist es appendReplacement ohne neue Zeichenkette aufzurufen und diese anschließend an den StringBuffer anzufügen:

matcher.appendReplacement(stringBuffer, "");
stringBuffer.append(group);

Bei dieser Variante müssen keine Zeichen maskiert werden. Die vom JDK angedachte Variante ist allerdings die der Nutzung von quoteReplacement, so das diese bevorzugt werden sollte.