5 Alben für die Insel

UPDATE: Sieht so aus, als würde meine bisherige Methode, “Tracksets” einzubinden, nicht mehr (überall?) funktionieren 😡 Der Trick scheint zu sein, in den Einstellungen -> erweiterte Einstellungen -> Öffnen von Spotify über Web-Links erlauben:

Unter Linux geht es gar nicht, auf dem Telefon auch nicht. Ich stelle nach und nach alles auf Playlists um, das dauert aber eine Weile. Ich melde mich.

Fünf Alben “für die einsame Insel”, ohne besondere oder wertende Reihenfolge. “In a nutshell” ist jeweils eine Spotify-Playlist mit fünf ausgewählten Songs des Albums (deren Skripte dürfen dazu nicht geblockt sein, Google Analytics leider auch nicht).

Long time no hear! Ich bin wieder dem alten Fehler verfallen und wollte einen Themenbeitrag machen… mit dem Ergebnis, drei angefangene Posts vor mir her zu schieben. Anyway, dann also durcheinander:

Doors – In Concert

Die Doors höre ich inzwischen selten, aber das war mal anders: Zu Jugendzeiten hatte ich ein Poster von Jim Morrison über dem Bett hängen 🙂 Und das Doppelalbum hier ist gleichzeitig ein Best of – wie es meiner Meinung nach sein sollte bei Live-Alben, zumindest, wenn es nur ein Livealbum gibt.

PS: Ich bin etwas abgewichen von der “5 Songs”-Policy, aber erstens handelt es sich in diesem Fall um ein Medley, und zweitens wäre mir das sonst auch egal 🙃

Bruce Springsteen – The Ghost of Tom Joad

Das Rolling Stone Magazine titelte damals “Quo Vadis, Bruce?” Dieses Album ist so ganz anders als die aus E-Street-Zeiten, aber meiner Meinung nach die konsequente Weiterentwicklung der Idee “Working Class”: Während es früher um Aufwachsen, den eigenen Platz im Leben oder den (Vietnam-) Krieg ging, wird es hier deutlich ruhiger, gesetzter (rein musikalisch jetzt mal, inhaltlich habe ich gerade nicht so den Überblick), aber auch melancholischer. Wie man halt so wird, wenn sich die vorherigen Themen nicht in jedem Detail nur zum positiven gewendet haben.

Neko Case – Fox Confessor Brings the Flood

Das hatten wir noch nicht?? Hätte ich nur (ein mal) fünf Alben, dieses wäre dabei. Habe ich ungefähr den ganzen Sommer 2006 gehört; zuerst über das großartige Radio Paradise (woher ich das Album auch kenne), dann habe ich die CD von meiner damaligen Freundin bekommen. Ich liebe Nekos Stimme immer noch, und/aber ganz besonders auf diesem Album… das mit 38 Minuten sehr kurz ist, die Zeit kann und sollte man sich nehmen!

Art Blakely – Moanin’

OK, noch mal kurz Jazz. Ich verspreche, das war’s dann auch erst mal; Jazz höre ich auch eher im Winter. Das Album hier wurde übrigens von Rudy Van Gelder überarbeitet, der letzten August gestorben ist, und soll hier als Aufhänger stehen, euch “alle” RVG Edition-Alben an’s Herz zu legen! Jazz ist extrem unübersichtlich, und ich bin da kein (!) Experte, aber meiner persönlichen Erfahrung nach bekommt man einen guten Überblick, wenn man sich Miles Davis aus dem verschiedenen Jahrzehnten anhört, sowie die RVG-Alben.

R.L. Burnside – A Bothered Mind

And now for something completely different: Robert Lee “R.L.” Burnside. Der hat im zarten Alter von ~45 Jahren seine ersten Aufnamen herausgebracht, aber auch das war schon 1967 😅 So richtig ging es wohl erst in den 90ern los, ich stecke da nicht im Detail drin, aber auf diesem konkreten Album arbeitet er (unter anderem) mit Kid Rock, was definitiv anders klingt, als es seine Alben wohl in den 60ern getan haben. Deshalb ist das Album auch auf meiner “White Trash”-Playlist, was nicht nur politisch, sondern auch auf jeder anderen Ebene falsch ist. Aber ich schweife ab. Blues, gemischt mit Kid-Rock-“Rap” und elektronischem Groove.

Note to self: Kid Rock brauchen wir unbedingt nächstes mal!

Pre-shared key Authentifizierung mit Spring Boot

Pre-Shared Keys sind mit Spring Boot eine Geschichte voller Missverständnisse. Hier jeweils meine:

HTTP/HTTPS

In der Theorie scheint die Verwendung von https “überflüssig”, denn wenn ich eh nur vorher als “vertrauenswürdig” zertifizierte Clients zulasse, warum dann noch die Verbindung absichern. Naheliegende Antwort: Austausch von Identitäten über http ist nie gut – ⚠

Also https in den application.properties (/application.yml) der Server-Anwendung einschalten:

Zertifikatserstellung

Die eigentliche Idee ist jetzt: Jeder Client muss ein “trusted” Zertifikat vorweisen. Diese Zertifikate werden in einem “Trust-Store” abgelegt, den der Server bekommt. Der Client bekommt sein Zertifikat ebenfalls, dort in einem “Key-Store”, um sich auszuweisen. Andersrum analog: Das Serverzertifikat bekommt der Client in einem Trust-Store, um den https-Server zu verifizieren, der Server legt das in seinem Key-Store ab.

Insgesamt sieht die Erstellung so aus:

Wichtig dabei: Die verwendeten Passwörter (klar), aber auch der verwendete Name, beides brauchen wir unten.

PS, siehe unten und hier

Zertifikate einbinden

Die Zertifikate kann man dem Server jetzt über einen TomcatConnector bekannt machen, muss man in Spring Boot aber nicht (⚠; Danke, Nils). Stattdessen genügt Folgendes, ebenfalls in den application.properties:

Hier verweise ich auf Key-Stores in der .jar, was seit Tomcat 7.0.66+ funktioniert. ⚠

In der Client-Anwendung sieht das etwas anders aus, zuerst die application.properties:

Verwendung dann beispielhaft in einem RestTemplate (org.apache.http.* gibt’s hier)

ACHTUNG: Der NoopHostnameVerifier war hier nötig, da ich das Zertifikat nicht mit expliziten Hostnames erstellt habe, in Production würde man das wohl tun. ⚠

Userverwaltung

Natürlich kann man mehrere Client-Zertifikate verwenden, und natürlich kann man jedem Client separate Rechte zuweisen. In der Server-Anwendung:

(Quelle und Stack Overflow)

btw: Spring Security bringt einen default User mit (“user”, Passwort wird auf der Konsole beim Hochfahren ausgegeben). Deaktivierung in den application.properties:

hth

Einzelhandel?

Wo heise gerade fragt, “wie sich der Laden um die Ecke gegen Amazon behaupten kann”, möchte ich drei exemplarische Beispiele dazu nennen, wie er es nicht kann:

Die Schutzbleche

Ich brauche neue Schutzbleche für mein Klapprad. Als vorbildlich lokal denkender Konsument fahre ich zu einem Fachhändler in der Lübecker Innenstadt. Ich werde dadurch eine Bahn später heimfahren, also eine Stunde “Verlust” haben. Ich zeige dem Händler das Rad, bestelle Schiutzbleche “für dieses Rad” und will ihm meine Telefonnummer geben. “Wozu? Mittwoch sind die da.” Alles klar.

Mittwoch: Ich fahre zum Händler – im Regen, wohlgemerkt. Überraschung, keine Schutzbleche. “Hier war so viel los, ich konnte die noch nicht bestellen”. Tja, hätte er mal meine Nummer aufgenommen, wäre das (so) nicht passiert. Danke für eine weitere Stunde Zeitverlust (im Regen).

Einige Tage später sind die Bleche da. Ich fahre wieder hin, hole sie ab, fahre deshalb ein weiteres mal eine Stunde später heim. Dort angekommen stelle ich fest: Die Bleche passen nicht. Warum habe ich dem Händler mein Fahrrad vor Ort gezeigt, live und in Farbe?

Ein vierter Besuch (=eine vierte Stunde Verlust), und ich habe mein Geld zurück. Zum Glück ohne Gemecker, allerdings auch ohne Entschuldigung.

Ich habe dann 20 Minuten online recherchiert, und genau passende Schutzbleche nach hause geliefert bekommen.

Der Schlauch

Weiteres Beispiel vom Klapprad, dieses mal bei einem Fachhändler in Ratzeburg (denn ich lerne ja dazu): Ich habe einen Platten, und weil die jährliche Inspektion ansteht, möchte ich den Reifenwechsel direkt miterledigen lassen. Ich gebe das Rad ab und hinterlasse meine Telefonnummer (denn ich lerne ja dazu). Versprochener Termin: Freitag; heute ist Dienstag. Oha, das wird ja nervig, so lange zu Fuß. Aber gut, so sei es.

Samstag gehe ich zum Händler – Überraschung: Das Fahrrad ist nicht fertig. Ein passender Schlauch wäre nicht aufzutreiben gewesen. Warum ist dann nicht zumindest die Inspektion fertig? Warum nicht sogar schon seit Tagen? Warum habe ich, so oder so, keinen Anruf bekommen? Man weiß das alles nicht. Montag ist Ruhetag, also ein weiterer Tag zu Fuß. Dienstag soll die Inspektion dann wirklich durch sein (ein weiterer Tag zu Fuß), großes Ehrenwort, dann könne man auch keine Anruf vergessen, denn auf jeden, jeden Fall, gleich als erstes, wird es Dienstag erledigt, kein Anruf notwendig.

Dienstag, ich rufe an (denn ich lerne ja dazu). Inspektion nicht fertig. Ich muss etwas ausfallend werden, als man mich erneut vertrösten will. Daraufhin verspricht mir der Inhaber (?), dass es doch heute noch klappt. Was auch der Fall ist, muss man fairerweise sagen. Eine Entschuldigung und einen Sonderpreis gibt’s auch; so komme ich zumindest wieder.

Ich habe dann 20 Minuten online recherchiert, und genau passende Schläuche (und einen Mantel) nach hause geliefert bekommen. War nicht mal schwer: Ich musste die Nummer vom aktuellen Mantel (steht auf dem Mantel) bei Google eintippen.

Der Teppich

Ebenfalls in Ratzeburg wollen wir zwei Teppiche bei einem großen, inhabergeführten Möbelhaus kaufen. Schön, dass es das so noch gibt!

Wir suchen uns ein gefälliges Exemplar aus und fragen nach den von uns benötigten Größen. Kurzes Telefonat vom Verkäufer, sorry, das wären Sondergrößen. Kann man bestellen, dauert aber 5 Monate, da handgeknüpft und so. Aber gut, Danke für die schnelle Info! Wir werden auf einen ausliegenden Prospekt mit Teppichen aufmerksam gemacht, “Lieferzeit 10 Tage” steht da drin. Das Prospekt nehmen wir mit, einige Tage später bestellen wir zwei Teppiche daraus, in Größen, wie sie im Prospekt beworben werden. Die Verkäuferin bietet Kontakt per Email an – sehr gerne, das ist meist unproblematischer, als im Büro (/Meeting) angerufen zu werden.

Ich interpretiere die “10 Tage” proaktiv als “10 Werktage”, Mittwoch wären die um. Freitag vorher habe ich aber noch so gar nichts gehört, nanu? Kontakt war ja per Email, alles klar, ich schreibe also eine Anfrage. Antwort kommt erst Montag (als PDF im Anhang einer ansonsten völlig leeren Mail ;-)):

Nach Rücksprache mit unserem Teppich-Lieferanten muß ich Ihnen leider mitteilen, das [sic!] die bestellten Teppiche zur Zeit eine Lieferzeit von 15 Wochen haben. Die Teppiche sind keine Lagerware und werden nach Kommisionen angefertigt. Bitte teilen Sie mir mit, ob Sie solange warten möchten.
Mit freundlichen Grüßen
Möbel-[…] KG

Aha. Warum kann das nicht ebenfalls innerhalb von Minuten per Telefon geklärt werden, so wie beim ersten mal? Warum muss ich das aktiv erfragen, nachdem die beworbene Lieferzeit schon fast erreicht ist? Apropos: Ist das schon irreführende Werbung? Zumal genau diese Größen beworben werden? Das möchte ich vom Sender wissen. Leider gibt es keinen Namen, ich antworte einfach auf die Email.

Doch ich bekomme einen Auto-Reply! Kann man sich gar nicht ausdenken: “Bitte teilen Sie mir mit, ob…”, und dann ab in den Urlaub. Ich schreibe eine erneute Mail an die Adresse des im Auto-Reply genannten Vertreters – keine Antwort. Genervt rufe ich am Folgetag an. Niemand weiß irgendwas, man würde sich melden.

~ einige Irrungen später ~

Ich bestelle die Teppiche “trotzdem”, erwünsche mir aber schon mal ein Nachdenken über den sicherlich angemessenen Preisnachlass. Es ist Anfang Juli.

~ einige Monate später ~

Ich werde informiert, dass die Teppiche da sind. Ich muss sie abholen, dazu muss ich mir einen Kombi leihen. Im Laden werde ich begrüßt mit den Worten “Ah Herr Kruse, schön, dass es jetzt doch gar nicht so lange gedauert hat!” Wir haben den 29. Oktober, ich versuche das deshalb nicht weiter zu kommentieren. Die Verkäuferin tippt den originalen Preis in die Kasse. Meine Frage nach dem bereits “angedrohten” Nachlass scheint sie zu überraschen: “Oh, ach, na, das habe ich jetzt nicht erfragt, einen Moment”. Sie verschwindet im Hinterzimmer, kommt kurz danach zurück, und verkauft mir die Teppiche für 1.150,– statt 1.168,– Euro. Keine Pointe. Ich hätte ja vom Vertrag zurücktreten können.

Ich halte fest: Ich habe Teppiche ausschließlich auf Basis von Fotos ausgesucht – wie ich es auch im Internet gekonnt und getan hätte. Dafür musste ich selber hinterherlaufen, die Ware selber abholen, und habe kein Umtauschrecht (Sonderanfertigung!). Der Laden hatte die Teppiche etwa 24h im Lager liegen, das war dann aber auch schon die ganze Leistung.

Fazit

Ich werde weiter lokal einkaufen, wenn der Preis nicht ganze Klassen höher ist als im Internet (Negativbeispiel: Eine Jeans kostet in einem großen Kaufhaus in Lübeck 99,–, bei Amazon 70,–). Aber das ist mein Wohlwollen, nicht die Leistung des Einzelhandels. Ich kann niemandem verübeln, den Sinn des Einzelhandels nicht nachvollziehen zu können.

Und was “Online recherchieren, offline kaufen” aus dem genannten Artikel angeht: Anfang diesen Jahres wollte ich eine elektrische Kettensäge kaufen. Aber da ich da keine Ahnung von habe, wollte ich die vorher in die Hand nehmen können. Kein Problem bei Amazon, ich kann alles immer zurückschicken. Sehr wohl ein Problem beim örtlichen Fachhandel für Gartengeräte: Obwohl ich bewusst nur zwei Modelle angefragt habe, und bewusst nur die beiden, deren Marken dieser Laden in großer Zahl führt, konnte man mir diese Modelle nicht in den Laden zur Anschauung bestellen. Bei Amazon hätte ich sie de facto für Wochen zum Ausprobieren daheim gehabt.

Tatsächlich habe ich aber die online ausgesuchte Säge offline gekauft, bei einem Fachhändler in Lübeck.

JNAerator und time_t

Nachtrag zu neulich: JNAerator macht aus einem time_t in etwa Folgendes (schon an Java Naming Conventions angepasst):

Damit kann man fast nichts anfangen; insbesondere bekommt man den Eigentlichen Timestamp nicht da raus. Das “Pointer” ist außerdem irreführend, denn C liefert an der Stelle keinen Pointer, sondern die Sekunden seit Epoch. Funktionieren tut:

Quelle, hth

JNAerator?

Das Anstrengende Fehleranfällige an JNI ist das Mapping von (komplexen) Datentypen. Nun gibt es aber auch noch JNA,

a community-developed library that provides Java programs easy access to native shared libraries without using the Java Native Interface.

(Wikipedia), und dafür insbesondere den “JNAerator“, der komplexe Datentypen “automatisch” mappt. Die Idee liegt nahe, statt JNI(-Strukturen) JNA(-Strukturen) zu nutzen. Im Folgenden ein Versuch.

Die Installation ist so weit klar:

Der Aufruf allerdings schon nicht mehr so sehr (“0.13” und den Pfad zum lokalen Maven-Repo ggf. anpassen):

Wichtig ist nämlich -runtime JNA, mit den default Einstellungen handelt man sich Abhängigkeiten zu org.bridj (laut Doku “faster runtime that supports C++”) und damit die Notwendigkeit ein, die dll darüber zu laden. Und das will man zumindest dann nicht, wenn man plain JNI möchte.

Das JNAerator Studio (hier) scheint das übrigens per default anders zu machen, aber das nur am Rande. Trotzdem für die Akten: Den Pfad zur dll würde man BridJ so bekannt machen:

Aber zurück zu den so kompilierten Klassen. -mode Directory erzeugt sie als .java-Dateien, nicht als .jar. Das ist hilfreich, denn man muss sie editieren, siehe unten. Sie enthalten (übrigens neben Kommentaren mit dem vollen Pfad der Quelldatei, im Beispiel also /some/path/to/some/HeaderFile.h, evt. will man den nicht öffentlich machen) dann alle structs in ihrer Java Version. Das eigentliche Interface, das die Methoden der Header-Datei bereitstellt, muss man trotzdem selber schreiben und wie folgt laden:

In MyInterface deklariert man die Methoden, auf die man in der dll zugreifen möchte. Primitive Übergabe-/Rückgabeparameter sind dabei ziemlich selbsterklärend (int=int, bool=boolean, etc.), Strings sind char-Arrays, Pointer bringt JNA mit (bsplw. IntByReference, IMHO ein Vorteil gegenüber JNI), structs hat man sich ja eben in Java-Klassen übersetzt. Also alles gut? Tatsächlich gibt es Probleme mit den erzeugten Klassen:

Einige sind offensichtlich, bsplw. überschreiben sie

mit

, was natürlich nicht kompiliert. Globales Suchen-und-Ersetzen, fertig.

Anderes ist schon komplexer: Structures (also die Java-Klasse jetzt) haben ein Alignment, im Konstruktor zu übergeben. Wenn ich das richtig verstehe, korrespondiert das mit der entsprechenden Compiler-Option in VS und sollte automatisch erkannt werden? Oder es hängt an der Plattform? Wie auch immer: Wenn man eine struct hat, die, sagen wir, 22 Byte belegt, dann ist es nicht hilfreich, wenn der default von 4 Byte großen Blöcken ausgeht. Entweder werden dann nämlich zwei Byte abgeschnitten, oder zwei unnötige Bytes angehängt, was zu Verschiebungen in der Folgestruktur führt!

Beispiel: In Arrays von structs beginnt der zweite Eintrag dann zwei Bytes zu spät (es fehlen zwei Bytes zu Beginn) oder zu früh (der Eintrag beginnt mit den letzten zwei Bytes aus dem ersten Eintrag). Nicht unbedingt einfach zu debuggen m( Hilfreich ist es, das System-Property jna.dump_memory auf true zu setzen, und die Ausgabe in einen Hex-Editor zu kopieren. Man sieht die beschriebenen Byte-Offsets dann wenigstens (Danke, Nils!).

Ich habe dazu eine eigene Zwischenschicht eingezogen:

Zusammenfassung

Ja, JNAerator erzeugt einem Java-Klassen aus Headerdateien. Und das ist bei sehr großen Headern auch hilfreich. Aber es ist auch sehr fehleranfällig – und teilweise sogar fehlerhaft. Es kann nur eine Basis für eigenen Code sein.

Update

Nachtrag zu time_t

Missing vcruntime140.dll / vcruntime140d.dll

Deine Visual Studio Anwendung beschwert sich über eine fehlende vcruntime140d.dll? Das “d” steht für debug, bitte als “Release”-Version kompilieren.

Deine Visual Studio Anwendung beschwert sich (nun) über eine fehlende vcruntime140.dll? Dann bitte das aktuelle Microsoft Visual C++ Redistributable Package installieren. Achtung: Ob x64 oder x86 entscheidet sich nicht an der Systemarchitektur, sondern an der Programm-Version! Also: Win32-Anwendung läuft nicht -> x86-Package installieren.

hth

C++ println

Dem nächsten, der mir erzählt, Strings wären in Java nicht ganz selbsterklärend (was sich im Wesentlichen darauf beschränkt, dass es keine Primitives sind), dem lach ich ins Gesicht und verweise ihn auf diese gewachsene String/char/…-Welt in C++.

Also. Modulo weiterer Anwendungsfälle, die ich dann ergänze, scheint Textausgabe wie folgt ganz gut zu funktionieren. Ich wollte an der Stelle kein printf verwenden, weil ich jede Ausgabe (zentral) prefixen wollte. Vermutlich könnte man printf einfach wrappen, indem man dessen Signatur kopiert, egal:

Aber bitte auch an den Anfang der Datei, sonst werden die Funktionen nicht gefunden m(

Update: Schön (wenn auch ohne Prefix) ist auch

Java: C/C++ über JNI einbinden

Neulich musste ich eine DLL aus Java heraus ansprechen. Zur Wahl stehen JNI und JNA, wobei JNA “nur” ein Wrapper für JNI ist – und bei mir nicht funktioniert hat. In der Theorie ist JNI aber auch nicht schwer, allerdings legt Visual Studio einem mir Steine in den Weg. Ein Grund mehr, bei Java zu bleiben.

Der Java-Teil ist dann auch denkbar einfach:

Diese DllBridge wird dann in eine Headerdatei übersetzt:

Und diese Header-Datei dann in “das” C/C++-Projekt kopiert. An “das” Projekt kommt man wie folgt:

  • Visual Studio installieren; ich habe Visual Studio Community 2017 mit den Standardkomponenten genommen
  • Neues C++/Win32-Projekt anlegen, im Dialog unter “Anwendungseinstellungen” den Anwendungstyp “DLL” wählen
  • Ich habe das Projekt testweise MyDll genannt, die entstehende .dll heißt später genauso

Nachdem man die DllBridge.h in das Projekt kopiert und über Rechtsklick > Include In Project eingebunden hat, kann man ihre Methoden implementieren. O.g. Code erzeugt genau eine Methode Java_DllBridge_hello, siehe DllBridge.h. Deren Implementierung in der .c-Datei:

Alleine die Importe und die korrekte Version von MessageBox herauszufinden, hat sicher eine Stunde gedauert 😡 Oh, Stichwort “Importe”: jni.h wird vom  JDK mitgebracht, die entsprechenden Ordner muss man in VS bekannt machen. Das funktioniert nicht über einen Symlink, sondern über die Projekteinstellungen, indem man unter Configuration Properties > C/C++ > General > Additional Include Directories diese drei Verzeichnisse hinzufügt (Rekursion wäre ja auch zu einfach.):

  • C:\Program Files (x86)\Java\jdk1.8.0_121\include
  • C:\Program Files (x86)\Java\jdk1.8.0_121\include\win32
  • C:\Program Files (x86)\Java\jdk1.8.0_121\include\win32\bridge
    PS Ja: Das ist ein 32-Bit-Java, weil ich letztlich eine 32Bit dll ansprechen will.

Das Ganze sollte jetzt bauen (Build > Build solution, oder STRG+Shift+B) und eine <Projektname>.dll erzeugen, siehe Konsolenausgabe. Der Name der .dll muss dem im initialen Java-Code entsprechen.

Ein Aufruf von

öffnet dann die MessageBox:

Sowie die erwartete Ausgabe auf der Konsole. Für reine C-Anbindung könnte man hier aufhören.

Interessant wird es nun, wenn man langlebigere C++-Objekte von Java aus referenzieren möchte. Idee:

  • Eine Klasse auf Java-Seite, die die dll lädt, sowie die nativen Methoden bereitstellt, und eine Klasse auf C++-Seite, die diese implementiert
  • Die C++-Klasse wird initialisiert, ihren Pointer gibt man in Form einer long an Java zurück (bzw. jlong, vgl. hier), vermutlich ist das die Speicheradresse
  • Über diese long kann Java dann das Objekt referenzieren
  • Braucht man das C++-Objekt nicht mehr, wird es deleted.

(via, längeres Beispiel, Danke Nils!)

Hier sieht das so aus:

Bzw. in C++:

Aufruf in Java dann:

Last but not least die andere Richtung, also C++ nach Java. Die Methode

lässt sich von C++ aus aufrufen über

Weiterführendes dazu hier.

hth