MvnIndex

January 17th, 2020

Der MvnIndex ist äusserst praktisch, wenn man ein neues Projekt mit Maven aufsetzt.
Neben einer “Artifact”-Websuche gibts auch ein Eclipse Plugin für die Suche nach GroupId, ArtifactId und Version.

Effective Java: Builder-Pattern

January 15th, 2020

7 Jahre nach der ersten Auflage ist das Buch “Effective Java” von Joshua Bloch nun endlich in der zweiten Auflage erschienen. Der Klassiker wurde komplett runderneuert: Best-Practises für ‘neue’ Sprachelemente wie Generics und Enums kamen hinzu, veraltete Kapitel (wie der Ersatz von C-Strukturen) wurden gestrichen.

Neu ist auch das “Builder-Pattern”. Es kommt zum Einsatz, wenn ein Objekt viele optionale Variablen besitzt. Die bisherige, klassische Variante bei solchen Objekten ist das Schreiben von mehreren Konstruktoren (’telescoping constructor’), die über unterschiedliche Anzahl von Parametern verfügen. Allerdings sinkt die Lesbarkeit bei mehr als 6 Parametern gewaltig (vor allem wenn die Parameter vom gleichen Typ sind).

Das “Builder-Pattern” verzichtet auf die ‘telescoping constructors’ und arbeitet stattdessen mit einer statischen inneren Klasse, die für das Erzeugen einer Instanz der äusseren Klasse zuständig ist. Der Konstruktor des Builder-Objekts enthält alle “Pflicht”-Variablen, die optionalen Variablen werden über (verkettbare) Methodenaufrufe hinzugefügt. Abschliessend wird die build Methode aufgerufen, die ein unveränderliches Objekt der äusseren Klasse erzeugt. Der Konstruktor der äusseren Klasse ist privat, d.h. nur ein Builder kann ein Objekt tatsächlich instanzieren:

Hier ein Beispiel:

  1. package ch.javablog.builderpattern;
  2.  
  3. import java.math.BigDecimal;
  4.  
  5. public class Product {
  6.         // all fields are final: immutable object
  7.         private final String id;
  8.         private final BigDecimal price;
  9.         private final String salesDescription;
  10.         private final Product baseProduct;
  11.         private final boolean approved;
  12.  
  13.         private Product (Builder builder) {
  14.                 // private Constructor can only be called from Builder
  15.                 this.id = builder.id;
  16.                 this.price = builder.price;
  17.                 this.salesDescription = builder.salesDescription;
  18.                 this.baseProduct = builder.baseProduct;
  19.                 this.approved = builder.approved;
  20.         }
  21.  
  22.         public String getId() {
  23.                 return id;
  24.         }
  25.  
  26.         public BigDecimal getPrice() {
  27.                 return price;
  28.         }
  29.  
  30.         public String getSalesDescription() {
  31.                 return salesDescription;
  32.         }
  33.  
  34.         public Product getBaseProduct() {
  35.                 return baseProduct;
  36.         }
  37.  
  38.         public boolean isApproved() {
  39.                 return approved;
  40.         }
  41.  
  42.         public static class Builder {
  43.                 // mandatory parameter
  44.                 private final String id;
  45.                 private final BigDecimal price;
  46.  
  47.                 // optional
  48.                 private String salesDescription = “”;
  49.                 private Product baseProduct     = null;
  50.                 private boolean approved        = true;
  51.  
  52.                 public Builder(String id, BigDecimal price) {
  53.                         this.id = id;
  54.                         this.price = price;
  55.                 }
  56.                 public Builder salesDescription(String salesDescription) {
  57.                         this.salesDescription = salesDescription;
  58.                         return this;
  59.                 }
  60.                 public Builder baseProduct(Product baseProduct) {
  61.                         this.baseProduct = baseProduct;
  62.                         return this;
  63.                 }
  64.                 public Builder approved(boolean approved) {
  65.                         this.approved = approved;
  66.                         return this;
  67.                 }
  68.  
  69.                 public Product build() {
  70.                         return new Product(this);
  71.                 }
  72.         }
  73. }
  74.  
  75. public class ProductClient {
  76.         public static void main(Stringargs) {
  77.                 BigDecimal price = BigDecimal.valueOf(36.5);
  78.                 Product.Builder builder = new Product.Builder(“050-0047”,price);
  79.                 // create Product using the builder
  80.                 Product p = builder
  81.                                 .salesDescription(“great product”)
  82.                                 .approved(false)
  83.                                 .build();
  84.         }
  85. }

Private Methoden in JavaScript dank Closures

January 10th, 2020

Momentan lese ich das Buch “JavaScript: The Good Parts” von Douglas Crockford.
Ein durchweg empfehlenswertes Buch, das eine klare und kompakte Übersicht über die Stärken (und Schwächen) von JavaScript bietet. Sehr interessant ist das “Functional”-Pattern: Mit Hilfe von Closures können private Instanzvariablen und Methoden definiert werden. In 4 Schritten erstellt eine sogenannte “Maker”-Methode eine neue Objekt-Instanz.
Erzeuge ein neues Objekt

Definiere in der Methode die (privaten) Instanzvariablen und Methoden.

Hänge an das neue Objekt die öffentlichen Methoden. Dank dem “Closure”-Prinzip haben nur diese Methoden Zugriff auf die vorher definierten Instanzvariablen und Methoden.

Gebe das neue Objekt zurück.
Hier das Beispiel:

  1. var vehicle = function(spec) {
  2.      // the spec object contains all attributes needed to create the object.
  3.  
  4.      // create a new empty object using the object literal
  5.      var o = {};    
  6.  
  7.      // vars of this function are the private variables of the new object
  8.      var age            = 0;
  9.      var maxSpeed       = spec.maxSpeed;
  10.      var name           = spec.name;
  11.      var price      = spec.price;
  12.  
  13.      // private methods
  14.      var calculateDegradation = function() {
  15.            return age * price / 10 ; // assuming linear degradation
  16.      };    
  17.  
  18.      // public methods
  19.      o.getName = function() {
  20.          return name;
  21.      };
  22.  
  23.      o.getMaxSpeed = function() {
  24.          return maxSpeed;
  25.      };
  26.  
  27.      o.setAge = function(v) {
  28.         age = v;
  29.         return o; // cascade pattern
  30.      }
  31.  
  32.      o.getResidualValue = function() {
  33.          return price – calculateDegradation();
  34.      };
  35.  
  36.      return o;
  37. }
  38.  
  39. var myVehicle = vehicle( { name: ‘Audi R8’,
  40.                                 price: ‘106400’,
  41.                                 maxSpeed: ‘301’});
  42.  
  43. alert(myVehicle.getMaxSpeed()); // 301
  44. alert(myVehicle.getResidualValue()); // 106400;
  45. alert(myVehicle.setAge(2).getResidualValue()); // 85120;

Interessant ist die Ansicht im Firebug: Keine Spur von den privaten Methoden oder Instanzvariablen. Sie werden durch das “Closure” geschützt.

trakkcor auf dem Nürburgring

January 5th, 2020

Alle paar Wochen bekomme ich EMails von trakkcor Anwendern, die mir beschreiben, wo und wie sie trakkcor einsetzen. Letzte Woche habe ich wohl vom bisher spannendsten Anwendungsfall erfahren:

Guten Tag,
Ich habe trakkcor letztes Wochenende erfolgreich zum Tracken eines Ford Escort RS2000 beim 500km Youngtimer-Rennen im Rahmenprogramm des 24 Stunden Rennens auf dem Nürburgring eingesetzt. Ich habe trakkcor einfach jede Sekunde ein GPS Signal holen lassen, dieses dann online in eine Datenbank gespeichert und mittels Google Earth “Netzwerklink” sekündlich auslesen lassen.
Daher erstmal ein großes Lob für die bisherige Arbeit, alles lief sowohl während den beiden 1,5 stündigen Traininssitzungen als auch im 4 stündigem Rennbetrieb stabil und ohne nennenswerte Probleme (Handy Sony Ericsson K700i, GPS Reciever Bluemax GPS-710).
Im laufendem Betrieb stellte sich heraus das eventuell eine Geschwindigkeits- bzw. Richtungsanzeige hilfreich bei der Visualisierung wären.
Ich würde mich daher sehr freuen, wenn in einem der nächsten trakkcor releases auch NMEA-Messages im GPRMC-Format übertragen werden könnten.
Falls gewünscht könnte ich ihnen Bildmaterial des trakkcor einsatzes zukommen lassen.

Mit freundlichen Grüßen
Gerrit Sturm

Sehr gerne… Wer sich davon ein Bild machen möchte, klickt hier, hier, hier, oder hier.
Solche EMails motivieren natürlich zur Weiterentwicklung von trakkcor. Im CSV befindet sich schon eine neuere Version, die aber nicht vollständig durchgetestet ist.

Folgende Features sind geplant:

  • Umschalten von HTTP POST auf HTTP GET (Es gibt mit manchen J2ME-Laufzeitumgebungen Probleme mit POST)
  • GPRMC-Support

Übrigens haben Hans-Dieter und Ralf Sturm das Youngtimer-Rennen wie auch im letzten Jahr gewonnen.
Herzlichen Glückwünsch!

;)

Top 7 der Eclipse Shortcuts

December 28th, 2019

In der IDE Eclipse gibt es eine Reihe Shortcuts, die das Programmieren beschleunigen. Die Liste der verfügbaren Shortcuts kann natürlich selbst auch mit einem Shortcut (CTRL+SHIFT+L) aufgerufen werden. Manche davon sind praktisch, manche nicht. Hier eine Liste meiner persönlichen Favoriten:

  • Rename / Refactoring (ALT+SHIFT+R) – Schnell eine Variable oder Methode umbenennen.
  • Open Resource (CTRL+SHIFT+R) – Zügig zu einer Datei springen.
  • Call Hierachy (CTRL+ALT+H) – Sehen, wo die aktuelle Methode aufgerufen wird.
  • Organize Imports(CTRL+SHIFT+O) – Imports aufräumen.
  • Next Editor (CTRL+F6)
  • Copy Lines (CTRL+ALT+DOWN)
  • Toggle Comment (CTRL+SHIFT+C)

OVal – the object validation framework for Java 5 or later

December 17th, 2019

Ich muss gestehen, ich bin ein Fan von defensiver Programmierung, d.h. ich deklariere mögliche Inkonsistenzen von Objekten durch das Werfen von RuntimeExceptions (z.B. IllegalStateException oder IllegalArgumentException). Praktisch finde ich ebenfalls das Prinzip der Unveränderlichkeit. Einmal erzeugt, soll das Objekt nicht mehr verändert werden. Somit werden Inkonsistenzen (z.B. nicht gesetzte Attribute) bereits im Vorfeld vermieden.

Allerdings verursacht diese Form der Absicherung unschönen Code-Overhead, da jeder Parameter manuell überprüft werden muss. Zudem stehen unveränderliche Objekte im Widerspruch mit der JavaBean Spezifikation

Vor kurzem habe ich einen interessanten Lösungsansatz im OVal Framework entdeckt. Hier werden die Properties und Methoden mit Annotations versehen und explizit oder implizit (via AspectJ) validiert. Beispiele gibts heute keine, stattdessen verweise ich auf die (gute) Doku.

Active Directory Virtualisierung mit Penrose

December 8th, 2019

Bei einem Projekt hatte ich die Problemstellung, dass Useraccounts aus zwei Active Directories in ein (javabasiertes) Shop-Produkt importiert werden sollen. Dieses Shop-Produkt wird zwar mit einer LDAP-Anbindung ausgeliefert, allerdings kann es nur Useraccounts aus genau einem Active Directory oder LDAP importieren.

Die Lösung: Ein LDAP-Proxy, der die beiden Active Directories zu einem virtuellen LDAP zusammenführt, und gleichzeitig LDAP-Binds erlaubt, um Single Sign On mit den Windows Credentials zu ermöglichen. Das (ebenfalls javabasierte) Open Source Produkt Penrose erfüllt genau diese Aufgabe.

Beispiel:
Active Directory 1 speichert die Kundenaccounts und besitzt folgenden Wurzelknoten:
dc=customer,dc=company,dc=com

Active Directory 2 speichert die Mitarbeiteraccounts und besitzt folgenden Wurzelknoten:
dc=employees,dc=company,dc=com

Im Penrose werden diese beiden Active Directory as LDAP Proxy Partitions importiert und die beiden Wurzelknoten in das Root DSE attribut eingetragen. Penrose simuliert keinen Active Directory, sondern lediglich einen “puren” LDAP. (Active Directory hat ein paar Spezialitäten, beispielsweise einen Bind mit der user@domain Notation). Dennoch werden Active Directory-spezifische Attribute wie memberOf übernommen. Man bekommt also einen LDAP mit Active Directory Schema.

Eine (wichtige) Kleinigkeit: Der Session Timeout in Penrose kann über die /conf/server.xml angepasst werden:

<session>
   <parameter>
      <param-name>maxIdleTime</param-name>
      <param-value>10080</param-value><!– time out von 7 tagen –>
   </parameter>
</session>

SCJP 6 Upgrade

November 27th, 2019

Letzte Woche habe ich das SCJP 6 Upgrade Exam bestanden.

Folgende Bücher habe ich während der Vorbereitungsphase durchgearbeitet:

  • Fast Track to Sun Certified Java Programmer (Scjp) 5.0 Upgrade Exam von Ka Iok Tong
  • SCJP Sun Certified Programmer for Java 5 Study Guide (Exam 310-055) von Kathy Sierra

Letzteres umfasst das komplette SCJP 5 und gibt Auskunft, welche Klassen und Methoden im Examen vorkommen können und welche nicht. Diese Hinweise vermisst man im “Fast Track to SCJP 5 Upgrade Exam” Buch. Hier wird beispielsweise die Klasse MessageFormat ausführlich beschrieben, obwohl sie für das Examen absolut irrelevant ist.

Bücher zum SCJP 6 gibt es noch keine, allerdings halten sich die Unterschiede zum SCJP 5 stark in Grenzen. Lediglich ein paar neue Klassen (NavigableMap, NavigableSet sowie Console) sind dazu gekommen.

Im Vergleich zum SCJP 1.4 sind die neuen Prüfungsthemen praxisbezogener. So wurden einige Klassen aus den Packages java.text und java.util.regex hinzugefügt. Als Konsequenz erhöht sich leider auch der Auswendiglern-Faktor (z.B. welche Konstruktor gibt es in der java.text.DateFormat Klasse ?)

Gleichzeitig wurden komplexe (aber dennoch spassige) Operatoren-Fragen wie Bitshifting oder Operatorvorrang gestrichen.

PKCS12 Zertifikate in Tomcat

October 19th, 2019

Apache Tomcat erlaubt neben den Java Keystore Zertifikaten auch das PKCS12-Format (PFX-Dateien), die von Windows 2003 generiert werden können (via SelfSSL) oder von einer CA bezogen werden. Eine Umkonvertierung von PFX-Dateien mit OpenSSL in Java Keystores über das PEM-Format (wie hier empfohlen) ist nicht notwendig!

Einfach in der server.xml das Zertifikat im Connector mit den Attributen keystoreFile, keystorePass und keystoreType konfigurieren:

  1. <Connector port=“9001”
  2.  maxHttpHeaderSize=“8192”
  3.                maxThreads=“150”
  4.                protocol=“org.apache.coyote.http11.Http11Protocol”
  5.                minThreads=“1”
  6.                minSpareThreads=“1”
  7.                maxSpareThreads=“75”
  8.                enableLookups=“false”
  9.                acceptCount=“100”
  10.                connectionTimeout=“20000”
  11.                disableUploadTimeout=“true”
  12.                URIEncoding=“UTF-8”
  13.                SSLEnabled=“true”
  14.                scheme=“https”
  15.                secure=“true”
  16.                clientAuth=“false”
  17.                sslProtocol = “TLS”
  18.                keystoreFile=“${catalina.base}/lib/zertifikat.pfx”
  19.                keystorePass=“meinpasswort”
  20.                keystoreType=“pkcs12”
  21. >

Hier noch eine Auflistung, welche Zertifikattypen die einzelnen Tomcat-Versionen unterstützen:

  • Tomcat 5.0: JKS, PKCS12
  • Tomcat 5.5: JKS, PKCS11 und PKCS12
  • Tomcat 6.0: JKS, PKCS11 und PKCS12

trakkcor-0.2.0-beta

September 16th, 2019

Eine neue Version steht zum Download bereit. Die Version 0.2 bietet Live-Tracking, d.h. die Applikation sendet in regelmässigen Abständen automatisch die Position an einen Server. Mehr dazu unter http://www.trakkcor.ch/development.html.
Wichtig ist noch zu erwähnen, dass vor dem Installieren der neuen Version das alte Midlet entfernt werden sollte, da die RecordStores nicht mehr kompatibel sind.
Viel Spass beim Ausprobieren.