Sonntag, November 17, 2019

Java, Date, Rest, Javascript,…

In der Aufzählung oben fehlen SpringBoot, WebComponents und irgendwas mit Containern oder Cloud. Also hier ist das Beispielprojekt auf Github. Die Anwendung mit

git clone git@github.com:gluehloch/springboot-demo.git

und

mvn clean package

bauen. Im Anschluss das gepackte Jar mit

java -jar ./target/restdemo-1.0.jar

starten. Unter der Adresse http://localhost:8080/demo/ping findet sich eine Response mit verschiedenen Datumsformaten wieder.

Die Anwendung verwendet Spring-Boot bzw. das eingebaute Jackson für die Serialisierung/Deserialisierung von Objekten. Über die application.properties kann das allgemeine Verhalten von Jackson eingestellt werden. Die folgenden Eigenschaften sind dafür zuständig:

spring.jackson.serialization.write_dates_as_timestamps = false
spring.jackson.date-format = yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone = Europe/Berlin

Ich denke, die Schalter oben sind weitestgehend selbsterklärend. Auf die Timezone/Länderkennzeichen würde ich nicht verzichten. Auch wenn mir bekannt ist, wo der Server steht und die Konsumenten vermutlich nur aus Deutschland kommen. Allein dieser Denkansatz ist diskutabel. In der Beispielanwendung habe ich mich für obigen Einstellungen entschieden. Für java.util.Date erhält man damit die folgende Ausgabe
Z.B. 2019-10-17 18:49:10. Wer es genauer mag, packt die Millisekunden mit hinten dran. Genauere Informationen finden sich in der Klasse PingDateTime. Dort habe ich verschiedene Datumsformaten hinterlegt.

Die nächsten Abschnitte gliedern sich in einen Server und einen Client Teil. Der Server ist mit Java und SpringBoot implementiert. Das Frontend besteht aus einer HTML und einer Javascript Datei.

Server

RestController:

Hier ein Auszug aus dem Spring-Boot RestController:

@RestController
@RequestMapping("/demo")
public class DateTimeController {

    @GetMapping("/ping")
    public PingDateTime ping() {
        PingDateTime pdt = new PingDateTime();
        pdt.setDateTime(new Date());
        return pdt;
    }

}

Interessant ist die Klasse PingDateTime. Für die Datum/String Transformation ist Jackson verantwortlich. Mit der Annotation @JsonFormat in der Klasse DateTimeJson wird der Serialisierungsprozess gesteuert. Out-of-the-box funktioniert die Annotation nur mit den Java Datentypen java.util.Date und java.time.LocalDate bzw. java.time.LocalDateTime. Für den Joda org.joda.time.DateTime Datentyp gibt es auf GitHub eine Extension für Jackson.

Fehlt die Annotation, versucht der Serialisierer Jackson eine Objekt-Dekonstruktion per Reflection. Im Falle von java.util.Date werden die Millisekunden (Unix-Timestamp) zurückgeliefert. In der Spring-Boot Anwendung wird dateTimeMillies formatiert ausgegeben trotz fehlender @JsonFormat Angabe. Das Joda DateTime Objekt erfährt bei der Serialisierung eine detailreiche Dekonstruktion, wenn nicht die oben genannten Extension verwendet wird.

Eine Bemerkung zu dem Kürzel "UTC". "UTC" ist die sogenannte Weltzeit (Coordinated Universal Time). Diese definiert keine Zeitzonen und gilt einheitlich auf der ganzen Welt. 'UTC' ist im strengen Sinne keine Zeitzone. Die Parameterbezeichnung 'timezone' für den Typ 'UTC' ist also nicht ganz korrekt. Die Verwendung von "UTC" hat dann einen Vorteil, wenn die Konsumenten in verschiedenen Zeitzonen sitzen.

Das Datumsangaben ohne Zeitzonen keine gute Idee sind, ist auch der Grund, warum java.util.Date durch java.time.LocalDateTime ersetzt werden sollte.

JSON Objekt

Das REST/JSON Modell mit den verschiedenen Formatangaben:

public class PingDateTime {

    // -- java.util.Date

    @JsonFormat(
        shape = JsonFormat.Shape.STRING,
        pattern = "dd.MM.yyyy HH:mm",
        locale = "de_DE",
        timezone = "Europe/Berlin")
    private Date dateTimeBerlin;

    @JsonFormat(shape =
        JsonFormat.Shape.STRING,
        pattern = "dd.MM.yyyy HH:mm:ss.SSSZ",
        locale = "de_DE",
        timezone = "Europe/Berlin")
    private Date dateTimeBerlinWithMilli;

    @JsonFormat(
        shape = JsonFormat.Shape.STRING,
        pattern = "dd.MM.yyyy HH:mm",
        locale = "de_DE",
        timezone = "UTC")
    private Date dateTimeUTC;

    private Date dateTimeWithoutFormatDefinition;

    // -- Joda DateTime

    @JsonFormat(
        shape = JsonFormat.Shape.STRING,
        pattern = "dd.MM.yyyy HH:mm",
        locale = "de_DE",
        timezone = "Europe/Berlin")
    private DateTime jodaDateTimeBerlin;

    // -- java.time.LocalDateTime

    @JsonFormat(
        shape = JsonFormat.Shape.STRING,
        pattern = "dd.MM.yyyy HH:mm",
        locale = "de_DE",
        timezone = "UTC")
    private LocalDateTime localDateTimeUTC;

    @JsonFormat(
        shape = JsonFormat.Shape.STRING,
        pattern = "dd.MM.yyyy HH:mm",
        locale = "de_DE",
        timezone = "Europe/Berlin")
    private LocalDateTime localDateTimeBerlin;

    // getter and setter ...

    /**
     * Initialisierung.
     */
    public void setDateTime(Date dateTime) {
        this.dateTimeUTC = dateTime;
        this.dateTimeBerlin = dateTime;
        this.dateTimeBerlinWithMilli = dateTime;
        this.dateTimeWithoutFormatDefinition = dateTime;
        this.localDateTimeUTC =
            dateTime.toInstant().atZone(ZoneId.of("UTC")).toLocalDateTime();
        this.localDateTimeBerlin =
            dateTime.toInstant().atZone(ZoneId.of("Europe/Berlin")).toLocalDateTime();
        this.jodaDateTimeBerlin = DateTime.now();
    }

}

In Projektverzeichnis findet sich die Datei rest.http. Wer VisualCode mit dem Rest-Plugin verwendet, kann sich mit Hilfe dieser Datei die Response bequem im Editor anschauen. Ebenfalls empfehlenswert ist das Tool httpie. Mit dem Kommandozeilenaufruf

http http://localhost:8080/demo/ping

erhält man eine nett formatierte Ausgabe der Response:

HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 15 Nov 2019 18:26:13 GMT
Connection: close

{
  "dateTimeBerlin": "15.11.2019 19:26",
  "dateTimeUTC": "15.11.2019 18:26",
  "dateTimeWithoutFormatDefinition": 1573842373004,
  "jodaDateTimeBerlin": "15.11.2019 19:26",
  "localDateTimeUTC": "15.11.2019 18:26",
  "localDateTimeBerlin": "15.11.2019 19:26"
}

Mit curl würde das natürlich auch funktionieren.

Client

Als Konsumenten für den REST Service habe ich mir eine kleine Javascript 'Anwendung' gebaut, die diesen Servie anzapft und die aktuelle Uhrzeit darstellt.

Der Client besteht aus zwei Dateien: index.html und DateTimeController.js. In der HTML Seite ist das Element <date-time></date-time> spannend. Das ist der Aufhänger für die WebComponent, die in der JS Datei definiert wird. Kurze Anmerkung: Im Internet Explorer oder im Browser Edge funktioniert das Beispiel nicht. Siehe canisuse.

WebComponent

In der Datei DateTimeController.js finden sich zwei Klassen. Einen Controller für das anzapfen des REST Services auf Server Seite. Interessant ist die Funktion date(). Diese definiert ein sogenanntes Promise. Aufgabe: Abfrage der REST Schnittstelle und im Erfolgsfall die Response nach JSON konvertieren oder eine Fehlermeldung in der Konsole ausgeben.

export default class DateTimeController {
    constructor() {
        this.$dateTime = null; // Hier speichern wir die aktuelle Uhrzeit.
    }

    date() {
        return new Promise((resolve, reject) => {
            fetch('./demo/ping').then(response => {
                    return response.json();
                }).then(data => {
                    resolve(data);
                }).catch(err => {
                    console.error(err);
                    reject(err);
                });
        });
    }

    getCurrentDateTime(callback) {
        this.date().then(dateTime => {
            this.storeDate(dateTime);
            callback(dateTime);
        })
    }

    storeDate(dateTime) {
        this.$dateTime = dateTime;
        console.log(dateTime);
    }
}

Im nächsten Schritt wird ein DOM Element angelegt. Dieses enthält den Button zur Abfrage der Uhrzeit und ein Ausgabeelement zur Anzeige der selbigen.

const template = document.createElement('template');
template.innerHTML = `<button>Get Time</button><br/><h3>Uhrzeit:</h3><div id="dateTime"></div>`;

Die WebComponent selbst findet sich im nächsten Code-Schnipsel:

class DateTimeElement extends HTMLElement {

    constructor() {
        super();
        this.dateTimeController = new DateTimeController();

        this._shadowRoot = this.attachShadow({ 'mode': 'open' });
        this._shadowRoot.appendChild(template.content.cloneNode(true));
        this.$dateTime = this._shadowRoot.querySelector('#dateTime');

        this.$getTimeButton = this._shadowRoot.querySelector('button');
        this.$getTimeButton.addEventListener('click', (e) => {
            this.getDateTime();
        });
    }

    getDateTime() {
        this.dateTimeController.getCurrentDateTime((dateTime) => {
            this.$dateTime.innerHTML = dateTime.dateTimeBerlinWithMilli;
        });
    }

    render(dateTime) {
        this.$dateTime.innerHTML = dateTime.dateTimeBerlin;
    }

    connectedCallback() {
        console.log('connected!');
    }

    disconnectedCallback() {
        console.log('disconnected!');
    }

    attributeChangedCallback(name, oldVal, newVal) {
        console.log(`Attribute: ${name} changed!`);
    }

    adoptedCallback() {
        console.log('adopted!');
    }
}

window.customElements.define('date-time', DateTimeElement);

Fertig.

AngularIO

Zum Abschluss und als Ergänzung: In AngularIO würde ich ein Javascript Date immer mit dem folgenden Ausdruck 'pipen':

{{model.dateTime | date: 'dd.MM.yyyy HH:mm': '+0000'}}

Referenzen:

Sonntag, Oktober 27, 2019

Windows Powershell Enhancements

DOS-Box: Next Generation

Wer als Entwickler behauptet, er arbeitet unter Windows, der erntet von seinen Linux/MacOS Kollegen ein müdes lächeln. Die Ursache dafür scheint allein in der vernachlässigten Shell zu liegen. Bei den IDEs sah es bei Microsoft nie schlecht aus. Eher war die Windows Plattform hier Vorreiter, wenn man an Tools wie Visual Studio oder Eclipse in früheren Jahren denkt.

In einer Sache sind Linux und MacOS den Windows Besitzern immer noch weit überlegen: Die Kommandozeile, Shell oder Terminal kann unter Linux / MacOS einfach mehr. Zwar kann der Windows Besitzer cygwin installieren, eine perfekte Integration ist das nicht (immer). Man denke nur an die unterschiedlichen Pfade: ‘/’ statt ‘\’. Mit oder ohne /cygwin Root. Oder die Tools die doppelt installiert werden, z.B. git oder ssh. Das hat mittlerweile auch Microsoft erkannt und rüstet an dieser Front auf, um (mehr) Entwickler auf die Windows Plattform zu ziehen. Eine der vielen Initiativen ist die Powershell. Ich bin kein Spezialist, was Shell Skripte anbelangt, aber so richtig anfreunden konnte ich mich mit der Powershell nie. Wenn ich Skripte unter Windows schreibe, dann für die ‘bash’ Shell unter Verwendung von cygwin. Aber ich komme vom Thema ab.

Windows Terminal

Das neue Angebot an die Windows Entwickler heißt Windows-Terminal. Die Applikation befindet sich in der Betaphase. Funktioniert allerdings zuverlässig: Windows Terminal Preview.

oh-my-zsh

Die heißeste Killer-Shell unter Linux ist momentan oh-my-zsh. Auch unter cygwin verfügbar. oh-my-zsh bietet neben den visuellen Eindrücken interessante Erweiterungen, die aus meiner Sicht, vor allem den Umgang mit GIT betreffen.

oh-my-posh / posh-git

Inspiriert von der oh-my-zsh Shell-Erweiterung, gibt es eine Variante für die Powershell. oh-my-posh bzw. posh-git.

oh-my-posh wird zusammen mit posh-git installiert. Bevor die Installation gestartet werden kann, muss vermutlich eine Sicherheitseinstellung der Powershell geändert werden. Dazu öffnet man als Administrator die Powershell und setzt den folgenden Befehl ab:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

Danach wechselt man wieder in die ‘normale’ Powershell (ohne Admin-Rechte) und kann die folgenden Befehle ausführen:

Install-Module posh-git -Scope CurrentUser
Install-Module oh-my-posh -Scope CurrentUser

Im Anschluss wird das ‘Theme’ gesetzt:

Set-Theme Agnoster

Das ist mein Favorit. Weitere Themes finden sich auf der Projektseite von oh-my-posh/themes.

Damit oh-my-posh bei jedem öffnen der Powershell gestartet wird, muss die Konfiguration angepasst werden.

notepad $PROFILE

und dort die Zeilen

Import-Module posh-git
Import-Module oh-my-posh
Set-Theme Agnoster

eintragen. Und falls ihr in ein GIT Verzeichnis wechselt, wird euch auffallen, dass einige GIT-Repo Informationen farblich dargstellt werden. Falls ihr nicht den passenden Zeichensatz installiert und ausgewählt habt, werden einige Zeichen falsch dargestellt, so wie bei mir. Im Anschluss installiert man sich den passenden Zeichensatz, ergänzt um die sogenannten ‘Powerline’ Symbole.

Powerline Fonts

Auf GitHub findet sich ein Powerline Repo. Das lokal auf die Platte clonen:

git clone https://github.com/powerline/fonts.git

und im Anschluss

cd fonts
.\install.ps1

starten und warten, bis alle Zeichensätze installiert sind. Oder man pickt sich nur die geneigten Zeichensätze heraus und installiert diese.

Zeichensatz einstellen

In der Powershell mit rechts klick auf die Titelzeile, Eigenschaften auswählen und dann auf den Reiter ‘Schriftart’ wechseln. Dort z.B. den Zeichensatz

"Noto Mono For Powerline"

auswählen. Im Windows Terminal geht man ebenfalls in die Titelzeile und klickt auf das Symbol rechts von ‘+’. Dort ‘Settings’ auswählen und notepad öffnet sich. Dort den Abschnitt ‘fontFace’ aus dem Beispiel kopieren und an gleicher Stelle einfügen.

// To view the default settings, hold "alt" while clicking on the "Settings" button.
// For documentation on these settings, see: https://aka.ms/terminal-documentation

{
    "$schema": "https://aka.ms/terminal-profiles-schema",

    "defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",

    "profiles":
    [
        {
            // Make changes here to the powershell.exe profile
            "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
            "name": "Windows PowerShell",
            "commandline": "powershell.exe",
            "hidden": false,
            "fontFace": "Noto Mono For Powerline",
            "fontSize": 12
        },
        {
            // Make changes here to the cmd.exe profile
            "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
            "name": "cmd",
            "commandline": "cmd.exe",
            "hidden": false
        },
        {
            "guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}",
            "hidden": false,
            "name": "Azure Cloud Shell",
            "source": "Windows.Terminal.Azure"
        }
    ],

    // Add custom color schemes to this array
    "schemes": [],

    // Add any keybinding overrides to this array.
    // To unbind a default keybinding, set the command to "unbound"
    "keybindings": []
}

Fertig.

Powershell ohne Powerline

Links und Referenzen

Donnerstag, Mai 30, 2019

Groovy Maven POM Checker

Für das Releasen eines Maven Projekts gibt es das Maven Release-Plugin. Also kein Grund das Rad neu zu erfinden?

Richtig. Naja. Also für eine kleine Übung mit Groovy ist das Thema perfekt. Technisch interessieren mich hier die folgenden Dinge:

  • Wie bekomme ich farbige Ausgaben auf die Konsole?
  • Wie leicht kann ich XML Dokumente mit Groovy einlesen?
  • Wie greife ich auf andere Command-Line Werkzeuge zu?

Das Ergebnis findet sich in meinem Repository auf GitHub: validate-pom.groovy.

Gleich zu Beginn definiere ich mir ein paar Helfer-Methoden, die die Konsolenausgaben bunt anpinseln. Die Farbgebung funktioniert übrigens nur in einer Cygwin Konsole. Unter Linux habe ich das bisher nicht ausprobiert. Mit einer Powershell funktioniert das jedenfalls nicht. Z.B.:

def red() {
    print "\033[31;1m"
}

In Zeile 38 öffne ich die pom.xml und suche nach allen SNAPSHOT Abhängigkeiten. Falls eine SNAPSHOT Abhängigkeit gefunden wird, wird diese mit gelben Textzeichen ausgegeben.

pom.dependencies.dependency.each { dependency ->
    if (dependency.version.toString().contains('SNAPSHOT')) {
        yellow()
        enableWarning = true
    }
    println "    ${dependency.groupId}:${dependency.artifactId}:${dependency.version}"
    reset()
}

Als nächstes wird die changes.xml untersucht. Ich untersuche das letzte release Element, ob dort das aktuelle Datum drin steht.

def changesXmlAsFile = new File("./src/changes/changes.xml")
def changesXml = new XmlSlurper().parse(changesXmlAsFile)
def lastReleaseElement = changesXml.body.release[0]
def today = new Date().format('yyyy-MM-dd')
if (lastReleaseElement.@date.toString().contains('??-??')) {
    enableWarning = true
    yellow()
    println "    Release date is undefined: ${lastReleaseElement.@date.toString()}"
    reset()
} else if (!lastReleaseElement.@date.toString().contains(today)) {
    enableWarning = true
    yellow();
    println "    Release date is not today: ${lastReleaseElement.@date.toString()}"
    reset()
} else {
    ok()
}

Im letzten Schritt wird git aufgerufen und geprüft, ob un-commited changes vorliegen.

def sout = new StringBuilder()
def serr = new StringBuilder()
def proc = 'git status'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println ""
println "Git repository:"
if (sout.toString().contains('git add')) {
    enableWarning = true
    yellow()
    println "    Uncommited changes! Check with git status."
} else {
    ok()
}

Ist das nicht der Fall, dann ist alles in Ordnung. Das Skript lässt sich natürlich wunderbar mit weiteren Funktionen erweitern. Wie oben bereits im Link angegeben, liegt das Skript in einem GIT Repository auf GitHub. In meiner Arbeitsumgebung habe ich das Projekt reingeclont. Im Anschluss passe ich die .bashrc an und lege einen alias auf das Skript. Z.B.:

alias pomcheck='groovy path.to.script/validate-pom.groovy

Fertig.

Freitag, Mai 03, 2019

Spring RestController und Exception Handling

Wer das erste mal einen klassischen Rest-Service mit Spring schreibt, also einen @RestController implementiert, der JSON (application/json; charset=utf-8) als Reponse ausliefert, kommt irgendwann auf die Idee, ebenfalls Fehlerzustände als JSON Response mit einem passenden HttpStatus Code auszuliefern.

Per Default erhält der Client den HTTP-Statuscode 500, wenn innerhalb des @RestController eine Exception geworfen wird. Das Ganze eingebettet in der Standardfehlerseite des Webservers. Als Antwort auf einen Restservice denkbar ungeeignet.

Eventuell möchte man einen Request auf die fachliche Korrektheit seiner Parameter überprüfen. Falls die Prüfung negativ ausfällt, sollen spezielle Http Status Codes (siehe Wikipedia HTTP StatusCodes) ausgeliefert werden. Z.B. könnte sich der Statuscode 400 BAD REQUEST oder 422 UNPROCESSABLE ENTITY für das Beispiel anbieten.

Wie sieht eine Implementierung dazu aus? Auf GitHub habe ich ein Beispielprojekt angelegt. Der Webservice nimmt Benutzer Registrierungen entgegen und vermerkt, ob der Benutzer dem Speichern von Cookies zugestimmt hat. Die Klasse de.awtools.registration.CookieController ist z.B. ein einfacher @RestController. Mit Spring hat man drei Möglichkeiten das beschriebene Problem zu lösen. Ich habe mich hier für die Lösung mit einem @ControllerAdvice entschieden. Das hat den Vorteil, dass dieser Advice für alle meine @RestController gilt. Der ControllerAdvice sieht folgendermaßen aus:

package de.awtools.registration.config;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import de.awtools.registration.RequestValidationException;

@ControllerAdvice
public class GlobalExceptionAdvice extends ResponseEntityExceptionHandler {

    @ExceptionHandler(value = { RequestValidationException.class })
    protected ResponseEntity<Object> handleConflict(Exception ex,
            WebRequest request) {

        String bodyOfResponse = "Unknown";
        if (ex instanceof RequestValidationException) {
            RequestValidationException rvex = (RequestValidationException) ex;
            bodyOfResponse = new StringBuilder().append('{')
                    .append("\"message\": \"")
                    .append(rvex.getValidation().getValidationCode().toString())
                    .append("\"").append('}').toString();
        }

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);

        return handleExceptionInternal(ex, bodyOfResponse,
                headers, HttpStatus.BAD_REQUEST, request);
    }

}

Hier werden alle Exceptions vom Typ RequestValidationException gefangen und ausgewertet. D.h. der Http-Statuscode 400 wird ausgeliefert und die Exception, bzw. die Nachricht aus der Exception, wird in ein einfaches JSON Objekt verpackt.

Weitere Beispiele und Erklärungen:

Samstag, Februar 23, 2019

Visual Studio Code Top Ten Extensions

Hier meine Top-Ten der wichtigsten Extensions für Visual Code:

  1. JSON Quicktype: Erstellt aus einem JSON Objekt, je nach ausgewählter Zielsprache, eine entsprechende Klassenstruktur. Im Prinzip wird versucht die Vorteile der statischen Generierung, wie man sie von einer WSDL Beschreibung her kennt, in die dynamische Welt der JSON Objekte zu transportieren. Insbesondere wenn eine typisierte Sprache wie Typescript oder Java verwendet wird, offenbaren sich die Vorteile, da eine IDE helfend eingreifen kann, in dem sie Eigenschaften bzw. Pfade zu Eigenschaften vorschlagen kann. Die Extension findet man hier: JSON Quicktype
  2. Visual Code kommt von Haus aus mit einer guten GIT Unterstützung daher. Dennoch gibt es einige sehr interssante Extensions zu dem Thema: Git History Diff
  3. Git Lens bietet Hover-Effekte an, um zu sehen, wer was in welcher Zeile geändert hat. Git Lens Supercharged
  4. Der Rest-Client war im letzten Post ein Thema. Rest-Client
  5. Indent Rainbow markiert farblichen Einrückungen. Interessant bei ‘klammerlosen’ Sprachen wie Python oder CSSS. Indent Rainbow
  6. TODO Highlight markiert TODO und FIXME Marker. TODO Highlight
  7. TODO Tree funktioniert ähnlich die TODO Highlight. TODO Tree
  8. Auto Close Tag. Schliessen oder umbenennen von Tags. Auto Close Tag
  9. Jetzt wird es schwierig. Vielleicht ist es eine gute Idee, Visual Code mit Extensions nicht zu überfrachten. Ob es eine kritische Anzahl von installierten Extensions gibt?
  10. Ab diesem Punkt schreibe ich selber meine Extensions. Möglicherweise bekomme ich dann ein Gefühl, wie sich Extensions im allgemeinen auf die IDE auswirken: Visual Code: Your First Extension

Bonus Runde:

  • Visual Code als GIT Editor einrichten. Vorher ist zu prüfen, ob code --help per Kommandozeile aufgerufen werden kann.

    git config --global core.editor "code --wait"
    
  • Visual Code als GIT Diff Tool einrichten:

    [diff]
        tool = default-difftool
    [difftool "default-difftool"]
        cmd = code --wait --diff $LOCAL $REMOTE
    

Sonntag, Februar 17, 2019

Visual Studio Code als Rest Client verwenden

  1. Visual Studio Code installieren. Visual Studio Code
  2. Die Erweiterung Rest-Client installieren.
  3. Einen bliebigen Workspace Folder anlegen und dort eine Datei anlegen, z.B. opendligadb.rest. Anhand der Dateiendung erkennt das Plugin, dass es für diese Datei zuständig ist und bietet im Editor ein paar Utilities an, z.B. das ‘Send Request’. Neben der Endung .rest wird auch .http von der Extension akzeptiert.
  4. Folgende Zeilen Code per Copy&Paste übernehmen und mit Ctrl-Alt R ausführen:
    POST http://www.openligadb.de/api/getmatchdata/bl1/2016/8 HTTP/1.1
    Accept: content-type: application/json
    
    oder falls eine Response im XML Format gewünscht ist (Fachbegriff Content Negotiation):
    POST http://www.openligadb.de/api/getmatchdata/bl1/2016/8 HTTP/1.1
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    
  5. Es geht ein Stück weit einfacher. https://example.com/comments/1 hinschreiben und Ctrl-Alt R eingeben. Nach der Ausführung des obigen Kommandos seht ihr die Fussballergebnisse von 2016 für den 8. Spieltag der Fussball Bundesliga.
  6. Mit # wird eine Kommentarzeile eingeleitet und es kann als Trennersymbol zwischen den verschiedenen Requests dienen. Beispiel:
    ### Request JSON response
    
    POST http://www.openligadb.de/api/getmatchdata/bl1/2016/8 HTTP/1.1
    Accept: content-type: application/json
    
    #### Request XML Response
    
    POST http://www.openligadb.de/api/getmatchdata/bl1/2016/8 HTTP/1.1
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    

Samstag, Februar 09, 2019

Docker Jenkins Update

Jenkins im Docker Container starten

  • Ein Verzeichnis auf dem lokalen Rechner anlegen. Ich gehe davon aus, dass auf einer Bash-Shell gearbeitet wird.
    mkdir -p $HOME/jenkins
    
  • Das Jenkins Image starten. Bei der Portnummer vergesse ich immer wieder, welche Zahl für welchen Host steht. Die erste Zahl bezeichnet den Port auf dem Docker Host. Die zweite Zahl nach dem Doppelpunkt den Port im Container.
    docker container run --name jenkins \
      -p 8080:8080 -p 50000:50000 \
      -v $HOME/jenkins:/var/jenkins_home \
      -d \
      jenkins
    
  • Das Passwort aufschreiben, welches jetzt angezeigt wird.
  • Browser öffnen mit der passenden IP Adresse. Bei mir läuft Docker in der Virtual Box auf einem Windows Pro Rechner. D.h. der Docker läuft in der Regel unter der IP Adresse 192.68.99.100.
    http://192.168.99.100:8080
    

Jenkins im Docker Container aktualisieren

  • Rechts oben im Browser seht ihr vielleicht eine rot unterlegte Zahl. Diese signalisiert, Jenkins möchte aktualisiert werden. Die Adresse des Download Links kopiert ihr.
  • Einloggen in den Docker Jenkins Container.
    docker container exec -u 0 -it jenkins bash
    
  • Das Update herunterladen. Dazu die kopierte Adresse aus dem vorletzten Schritt auf der Kommandozeile eingeben.
    wget http://updates.jenkins-ci.org/download/war/2.150.2/jenkins.war
    
  • Diese Datei an den richtigen Ort verschieben.
    mv ./jenkins.war /usr/share/jenkins
    
  • Berechtigung ändern.
    chown jenkins:jenkins /usr/share/jenkins/jenkins.war
    
  • Container verlassen und neu starten.
    exit
    docker container restart jenkins
    

Quelle Docker/Jenkins

Donnerstag, Februar 07, 2019

Kommunikation

Kommunikation

5 wichtige Wörter für die Kommunikation:
  • Weil
  • Danke
  • Ich verstehe dich
  • gerne
  • Wir
Gelernt in einem Video aus der Redefabrik: Youtube.

Sonntag, Januar 27, 2019

Spring Data Jdbc

SpringJDBCData.md

Es gibt einen neuen Ansatz zur Lösung der Persistenz Problematik:

Spring Data JDBC

Der Ansatz orientiert sich weg von schwergewichtigen Persistenzlösungen wie Hibernate, EclipseLink oder allgemein von JPA. Im Mittelpunkt steht das sogenannte Aggregat, eine Idee von Eric Evans, dem Miterfinder des Domain-Driven-Designs. Das Aggregat umfasst verschiedene (Java-) Objekte oder Entities, die eine gemeinsame fachliche Domäne teilen. Ein weiteres Kennzeichen ist der gemeinsame Lebenszyklus dieser Entities. Den Einstiegspunkt in das Aggregat nennt man die Aggregat-Wurzel.

Das Aggregat bildet also einen abgeschlossenen, fachlichen Objektbaum. Das Repository setzt eine persistente Klammer um das Aggregat. Die Methoden des Repository nehmen die Aggregat Wurzel als Objekt entgegen, aktualisieren das Aggregat gegen die Datenbank oder liefern dieses als Ergebnis eines Finder-Aufrufs zurück.

Die Fachlichkeit, die auf das Aggregat zugreift, verwendet die aus Spring Data bekannten Repositories. D.h. man definiert ein Interface und Spring generiert an Hand der Methodensignaturen die passenden SQL Abfragen.

Die interessantesten Eigenschaften kurz zusammengefasst:

  • In Spring Data JDBC gibt es keine impliziten Transaktionsgrenzen. D.h. der aufrufende Code ist für das sinnvolle setzen von Commits und Rollbacks zuständig.
  • Kein Lazy Loading. Wenn eine Entity per SQL geladen wird, ist sie mit allen abhängigen Entities geladen.
  • Es gibt keine Sessions und kein ‘Dirty’ Flag der Entity, die entscheiden, wann eine Entity gespeichert wird.

Links und noch mehr Links…

AssertJ und java.util.List

AssertJ hat eine praktische Möglichkeit, Listen in JUnit Tests abzuprüfen. Insbesondere, wenn in der Liste komplexe Objekte abgelegt sind, s...