Gabi und Sascha
Kategorien : Alle | Berlin | Bücher | Fotografie | Java | Linkhalde | Weichware | Verfassung
[ZWEI JUNGS (14-17 JAHRE) SPIELEN IM REGEN AUF DEM ALEXANDERPLATZ.]
 

Nachdem der Git Daemon extra mittels


    $ sudo yum install -y git-daemon

nachinstalliert wurde, schlagen Netzwerkverbindungen zum pullen/fetchen der Repositorydaten fehl.

CentOS 7 ist etwas strenger was die Sicherheit angeht. Der Git Daemon dort lauscht zwar standardmässig an Port 9418, kann aber nicht von aussen angefragt werden. Fehlermeldung: "Connection refused". Die Firewall hat zugeschlagen. Damit es doch geht die Firewall-Zone auf 'trusted' stellen. Achtung: das kann Angreifern eventuell Tür und Tor öffnen.

Ich lasse CentOS 7 in einer gebridgten VM laufen, damit Kollegen mittels Git auf die Repositories zugreifen können. Siehe auch Mit Git und Lieutenantsystem auf master entwickeln.

Die Firewall-Zone kann über 'Systemwerkzeuge → Einstellungen → Netzwerk → Kabelgebunden → Options (kleines Sternicon unten rechts) → Identität → Firewall-Zone' eingestellt werden. Bitte auf das korrekte Netzwerkinterface achten.

Git dezentraler Ansatz eignet sich hervorragend für die schnelle Entwicklung im CD (Continuous Delivery) Umfeld. Leider wird Git in den meisten Ent­wicklungs­prozessen als zentralistisches Versions­verwaltungs­werk­zeug eingesetzt und verliert damit seinen entscheidenden Vorteil gegenüber Systemen wie zum Beispiel Subversion.

Im CD Umfeld macht es Sinn nur auf master zu entwickeln. Insbesondere wenn zum Beispiel nur Inhouse Projekte entwickelt werden. Branches haben die unangenehme Eigen­schaft, dass sie zu grossen Än­derungen verleiten und damit ein CD System konter­karieren.

Da meiner Meinung nach ein zentrales Repository für CI (Continuous Integration) System wie Jenkins oder Bamboo Sinn macht musst der Prozess des ausschliesslichen entwickeln auf master durch den Einsatz der dezentralen Möglichkeiten von Git umgesetzt werden.

Grösstes Problem ist der Austausch der entwickelten Artefakte zwischen den Entwicklern ohne über ein zentrales Repository zu gehen, wenn Branches nicht gewünscht sind und jeder Commit auf dem zentralen master einen Release Build mit anschliessendem Blau-Grün Deployment auslöst.

Für diese Problem bringt Git die nötigen Werkzeuge von Haus aus mit.

Lokales Repository remote verfügbar machen


    $ mkdir repos
    $ cd repos
    $ git daemon --base-path=. --export-all --verbose

In der erste Zeile wird ein neues Verzeichnis für die Repositories angelegt und dan in das Verzeichnis gewechselt. In dieses Verzeichnis werden später die remote-Repositories mittels git clone oder mittels git fetch geholt.

Entscheidend ist die letzte Zeile. Mittels git daemonwird ein einfacher Git interner Server (Daemon) gestartet. Dieser lauscht per default auf Port 9418.

Die Kommandoschalter und ihre Bedeutung im Einzelnen:

  • --base-path - exportiert Repositories aus dem angegebenen Ordner. In diesem Fall das Verzeichnis in dem der Daemon gestartet wird.
  • --export-all - exportiert alle Repositories im angegebenen Ordner.
  • --verbose - Jede Operation auf dem Server wird auf der Konsole ausgegeben.

Darüber hinaus bietet das daemon Unterkommando noch weitere Schalter. Diese sind im ersten Schritt allerdings nicht wichtig.

Der lauschende Daemon meldet sich mit der PID und der Meldung 'Ready to rumble'.

In einer weiteren Konsole clont der Entwicker isk jetzt ein Repository vom zentralen Git Server im repos Verzeichnis:


    $ cd repos
    $ git clone http://cetral.repo/general_problem_solver.git

Die entfernte Git Clients der Kollegen können jetzt beginnen anonym fetch und clone Operationen auf den Repositories in repos Verzeichnis auszuführen. push Operationen sind nicht möglich. push Operationen müssen explizit mittels Kommandozeilenparameter erlaubt werden.

Lieutenant fetcht mittels remote Verbindung

Angenommen ein Kollege hat bereits den master Branch des zentralen Repositories geclont (origin). Der er aktuell der Lieutenant ist und als einziger in den zentralen master Branch pushen darf, muss er den Entwicklungsstand der Kollegen auf Zuruf mittels fetch ziehen können. Hierzu richtet mittels des Git remote Kommandos eine entfernte Verbindung ein. Dabei wird der Verbindung ein bestimmter Name gegeben.


    $ git init
    Initialized empty Git repository in /home/sascha/repos/.git/
    $ git remote add isk git://192.168.1.127/general_problem_solver

IP Adressen und Namen können einfach per Chat ausgetauscht werden.

Bevor eine remote Verbindung zugefügt werden kann, muss ein leeres Verzeichnis mittels git init initialisiert werden. Ansonsten meldet git remote add … einen Fehler.

Ist das Verzeichnis initialisiert, wird die remote Verbindung eingerichtet.

Wichtig: die Endung .git fehlt im Verzeichnisnamen des entfernten Git Repositories.


    $ git fetch isk

Das Kommando zieht jetzt den Inhalt des entfernte Repositories. Mittels eines git checkout master wird in den master Branch gewechselt. Änderungen können einem Review unterzogen werden. Nach einem erfolgreichen Testlauf werden die Änderungen in das zentrale Repository gepusht. Das CI-System kann die Build- und Deploymentpipeline starten. Wurde das Blue-Green Deployment erfolgreich durchgeführt, kann ein eventuell anhängiges Ticket approved werden.

Und dann war da noch der Astrophysiker, der als Softwarearchitekt arbeitete. «Es gibt keine Softwarearchitektur.» war sein Mantra, «Alles organisiert sich von selbst. Wie das Universum.» Kann sein, war mein Gedanke und antwortete: «Klar. Das Universum hatte auch 13 Milliarden Jahre Zeit. Bin mir nicht sicher, ob die Firma so lange Zeit hat.» Hatte sie nicht.

Ich hatte einen komischen Traum. Ich bin im Grunewald spazieren gegangen. Plötzlich stand ich vor einem verlassenen Gelände des U.S. Militärs, ein Lauschposten, direkt an der Grenze, die durch den angrenzenden Bach ging. Das Gebäude stand und sah aus wie ein überdimensionierter, weisser Bienenkorb. Neben dem Eingang in den Bienenkorb, der eine Eichentür war, hing eine Gedenktafel auf der Stand: «Dem Gedenken an die Opfer des übermässigen Genusses der Betelnuss.» Darunter waren die Namen und Geburts- und Sterbedaten einer Familie in blauer Schrift auf weisser Emaille. Die Namen waren persisch - oder was ich mir einbilde persisch zu sein. Ein Toter war ein 13 jähriger Junge, er starb am 14.5.1978. Seine Eltern starben am 17.5.1978. An die Geburtsdaten kann ich mich mehr erinnern, nur noch an den des Sohn und dass der Vater 78 Jahre alt geworden ist.

Als ich wach geworden bin, musste ich mich erst mal schlau machen, was die Betelnuss genau ist. Ich verbinde nichts mit den beiden Tagen im Mai 1978. Ich war noch nie im Grunewald.

[KINDER SPIELEN IN "LA CALETA" AUF TENERIFFA VOLLEYBALL AUF EINEM PLATZ VOR HÄUSERN. EIN MÄDCHEN RENNT DYNAMISCH DEM BALL HINTERHER UND VERSUCHT IHN ZU BAGGERN.]
 

["ANDROID GBC BALL COUNTER LOGO - BÄLLE (FUSSBALL, BASKELBALL) IN EINEM SIGMA ZEICHEN.] In the last few weeks I had developed an Android based counter for Lego® Great Ball Contraption systems. The counter should measure contactless the throughput of passing balls.

The hypothesis was: a colored or white Lego ball moves in front of a black background. The Android system camera captures every X milliseconds an image. The first image is captured with no passing ball and the image data is stored in memory for comparison. Every following image is checked for color changed against the first image. If the amount of pixels with a changed color (against the background from the first image) reached a percentage threshold, the ball count will be increased by one. Because of the camera sensor noise the color change value must also reach a threshold to be measured. In the implementation these two parameters can be configured. This improves the detection rate depending on the light environment of the GBC setup.

Measure the color change also reduces false positive ball counts because of environment light changes.

Nevertheless, Lego® also offers not only colored balls but also black and white only balls (footballs/soccer balls). If the user has also black and white balls he can also switch on a brightness detection based on the luminance. This follows the same rules like the color change detection but has a different threshold configuration parameter. Usage of the brightness detection might increase the false positive rate.

After a ball detection

After the systems has detected a passing ball in front of the camera, the system stops analyzing the given images for an amount of time. Otherwise it might happen that the same ball is counted twice.

The delay is depending on the layout of the GBC system and for this the delay time is also configurable.

Two good parameters are:

Capture delay
Delay between two image captures of the camera.
Value: 30ms
Capture delay after detection
The delay of time between the detection of a ball in an image and the next time checking again for a passing ball.
Value: 150ms

This allows a theoretical throughput of 5 Lego balls per second. Note: GBC is defined with 1 Lego ball per second. But as you know we ignore the standard in our constructions. Because of this the Android GBC Ball Counter implementation contains also a balls per second calculation.

Limitation

[SCREENSHOT ANDROID GBC BALL COUNTER] If two balls are passing very close succession there are false negative counts. This means, the two balls are counted as one ball. This is the greatest limitation of this non-contact method. The problem can be limited only by structural measures on GBC system.

Implementation

Image format

I use the YUV 4:2:0 8 bit image format delivered by the Camera2 Android API. This API was introduced with Android 5.0 (Lollipop).

The YUV image format has some advantages over the JPEG format: it doesn't pipe the image data through the RGB calculation and compression routines which takes a lot of time and other resources and doesn't produce more important information.

Android 5.0 Bug

Due to a bug in Android 5.0 the YUV subsystem doesn't deliver correct UV (chrominance) information. only the first 600+ bytes contains color information. The rest of the bytes are always zero. Only the Y (luminance) values are correct. This means: for Android 5.0 the implementation only supports the brightness ball passing detection algorithm.

More information

The implementation of the GBC is open source under the terms of the GNU General Public License 3 and the source code is available on Github. There you can dive deeper into the ball detection strategy.

How it works in practice

[EINE DUNKELHAARIGE FRAU STEHT AN EINER MAUER (BERLINER MAUAER - EAST SIDE GALERY) UND ZÜNDET SICH EINE ZIGARETTE AN. DABEI BEUGT SIE SICH VOR UND HAT IHR LINKES BEIN AN DIE WAND GEWINKELT.]
 

Ich habe heute Android 6.0 (Marshmallow) auf meinem Motorola Moto G (2. Generation) installiert. Hauptsächlich wegen eines Bugfixes im YUV_420_888 Image capturing. Das Camera2 API liefert bei Android 5.0 (Lollipop) keine korrekte Farbinformation (siehe auch hier). Diese Farbinformation benötigt ich aber, um den Lego® GBC Ball Counter weiter zu optimieren.

Bei der Installation hatte ich angegeben, dass die SD-Card als interner Speicher verwendet werden soll. Dadurch werden Daten beispielsweise nicht im Speicher des Smartphone gespeichert, sondern auf der Speicherkarte selbst. Vorteil: der interne Speicher des Gerätes wird weniger belastet. Nachteil: mit dem Android Device Monitor aus dem Android Studio kann ich nicht mehr direkt auf das Verzeichnis "/storage/emulated/0/Android/data/de.speexx.lego.gbc.ballcounter/files" zugreifen. Damit kann ich nicht einfach die Beispielbilder, die ich gespeichert habe, herunter laden.

Android 6.0 kann die Daten trotzdem erreichen und kopieren. Dazu muss ich die Einstellungen öffnen. Und dort dann über

Speicher & USB → SD‑Karte von SanDisk* → Erkunden → Android → data → de.speexx.lego.gbc.ballcounter

navigieren. Im Unterverzeichnis files liegen dann die erzeugten *.yuv Dateien.

Da Android mit der Endung yuv nichts anfangen kann, können die Dateien auch nicht geöffnet werden. Allerdings können sie mit einem längeren berühren des Namens ausgewählt werden, auch mehrere Dateien. Die so ausgewählten Dateien können dann geteilt werden. Ich habe die Dateien in Google Drive geteilt und dann von dort wieder herunter geladen.

Ziemlich komplizierte Prozedur und sicherlich nicht für die regelmässige Anwendung geeignet.

Gute Nachricht

Die Chrominanzwerte U und V sind jetzt vorhanden und auch die Strides Angaben machen jetzt Sinn: jeweils 4 Luminanzwerte mit einem U und einem V Wert.

Todo

In den nächsten Tagen werden ich den GBC Ball Counter aufwärtskompatibel anpassen.


* Name SanDisk kann eventuell abweichen.

[PANORAMASICHT ÜBER BERLIN]
 

Wir waren auf dem Heimweg. Von Opa. Wir machen Heilgabend immer einen kurzen Spaziergang. Denn der Weihnachtsmann kommt bei uns nur, wenn niemand in der Wohnung ist. Diesmal sind wir über den Hausburgspielplatz zurück gegangen. Von dort können wir sehen, ob in der Wohnung Licht an ist. Immer ein untrügliches Zeichen für das Kind: der Weihnachtsmann war da.

In der Otto-Ostrowski-Straße hielt uns gegenüber plötzlich ein Caddy an. Aus den Augenwinkeln sah ich: der Weihnachtsmann sass hinterm Steuer. Wir schauten genau hin. Und tatsächlich, ein Weihnachtsmann stieg aus dem Auto einer Elektroinstallationsfirma. Fasziniert schaute das Kind hin. Und dann passierte es: der Weihnachtsmann sah uns und winkte uns zu sich her. Er erzählte uns, dass der Schlitten einen Defekt hat und er deswegen auf das Auto umsteigen musste. Dann stellte er mir die Frage, ob ich auch artig gewesen bin im letzten Jahr. Am Ende wühlte er in seinem Sack. Ganz tief unten fand er ein Geschenk für das Kind. Einen Ring mit blinkenden LED Lichtern. Das Kind war sprachlos. Hatte es bis jetzt vielleicht leichte Zweifel, dass es den Weihnachtsmann wirklich gibt, so waren diese jetzt vollkommen zerstreut.

Für solche Dinge liebe ich diese Stadt. Völlig ungeplant erscheint der Weihnachtsmann an Heiligabend wie aus dem Nichts und dann gibt es auch noch ein Geschenk.

[EIN MANN STEHT VOR EINEM KIOSK UND SCHEINT ETWAS ZU KAUFEN. DER KIOSK HAT KEINE EINGANGSTÜR, SONDERN NUR EINE KLEINE VERKAUFSLUKE. ÜBER DER VERKAUFSLUKE STEHT HANDGESCHRIEBEN: "VERKAUF HIER"]
 

I've created a Lego Digital Designer model for the Ferris wheel of the Lego GBC Kugelbahn #5.

Download

LEGO MODEL

Find our implementation of the Akiyuky Train design of the Kugelbahn #5 here. The blog post also contains downloadable LXF files for LDD.


Supplement: Due to an issue with LDD (version 4.3.8 and 4.3.9, Mac OS) it might happen that 6 parts are removed when opening the LXF file again. The parts are perfectly connected in the virtual model and in the real world model. I've no idea why this happen.

The following image shows the central parts (6558) removed by the program circled orange. These parts and one of the attached liftarms (32525) to these parts are central component of the wheel to work correct.

LEGO MODEL
 

Our last Lego GBC build, Kugelbahn #5, has a train module based on the design of Kawaguchi Akiyuky. The module with the tipping function, based on the idea of our daughter.

The design contains a train module which changes its direction autonomous. The train may also trigger further actions at direction change time. The gear system must transmit huge power from the motor to the direction change part. And there the gear system has a weak point in the following figure below orange circled.

LEGO MODEL

If this part is not build solid, the gear-wheels overrunning very fast. We need a couple of tries to build this part solid in a way that this not happen. I've created a Lego Digital Designer model for you. It shows out implementation of the Akiyuky design of the train. Rebuilding the design is very simple.

You can download the LDD file from here.

LEGO MODEL

The whole model must not been built filigran. The train must have a big weight, so that the Lego train wheels do not spin. I propose to move the battery box toward more to the drive wheels in our model. That may only bring a little more grip and makes the model a little more reliable.

An additional weak point - were I found no proper solution yet - is the suspension of the driving wheels. The axes become loose over time and travels on straight line press on after about 30-50 again. With curvy rails more often.

LEGO MODEL

Finally a simple LDD model for the direction change module. It's straight forward. We use the Lego Technic Knob-Wheels (32072) to press a Shock Absorber 9.5L Soft Spring (2909c03).

LEGO MODEL

Download

BLÜTE (GELB) SEHR WEICH AUFGENOMMEN VOR GRÜNEM HINTERGRUND. DIE BLÜTE UND IHRE BLÄTTER IST NUR ZU ERAHNEN]
 

Unsere Kugelbahn Nummer 5 ist fertig geworden. Nach langer Zeit der Optimierungen. Ziel war es diesmal die Kugeln mit einem niedrigen Drehmoment und einem hohen Drehmoment weiter zu befördern.

Accelerator

Der Accelerator ist das Element mit dem niedrigen Drehmoment. Die Umdrehung des Motor (ca. 275 U/min) wurde mittels Zahnräder auf ca. 4100 U/min gebracht und damit das Gummirad angetrieben. Dabei gab es in den ersten Stunden sehr viel seitlichen Abrieb am Rad. Die Ganze Bahn war voller Gummiteile. Dann hatten wir das Spiel im Griff und der Abrieb wurde minimal.

Der Accelerator kann eine Kugel nach vorne Beschleunigen. Allerdings reicht die Energie nicht aus grosse Höhenunterschiede zu überwinden.

Hammer

Der Hammer ist das Element mit dem hohen Drehmoment. Da er ca. 1 U/sec macht, dient er gleichzeitig als Mengenbegrenzer. Beim Hammer ist es wichtig, dass die Kugeln nacheinander zugeführt werden, da er immer nur ein oder maximal zwei Kugeln über die Distanz nach oben Beschleunigen kann.

Riesenrad

Das Riesenrad haben wir gebaut, weil wir es konnten :-) Das Rad mit dem Antrieb zu bauen ist eher eine Fingerübung. Die Aufnahme der Kugel hat sich allerdings als kniffelig herausgestellt. Daran haben wir mehrere Tage gebastelt. Das hatten wir völlig unterschätzt.

Das Riesenrad transportiert die Kugeln auch mit ca. 1 Kugel pro Sekunde nach oben.

Zug mit automatischer Richtungsänderung

Vom Riesenrad geht es in das Bahnelement. Zentraler Baustein ist der über Batterie angetriebene Zug, der automatisch den Richtungswechsel vornimmt. Für die Richtungswechseleinheit haben wird als einziges Element Bausteine zukaufen müssen, den Shock Absorber. Nach einigem experimentieren haben wir uns für den 9.5L Soft Spring entschieden. Kniffelig war hier die Kraftübertragung. Am geeignetsten hat sich das Knob Wheel (32072) herausgestellt.

Beim Zug war die Herausforderung es stabil und klein zu bauen. Gerade wenn der Zug den Richtungswechsel durchführt treten starke Kräfte auf, die die Zahnräder durchdrehen lassen und die ganze Konstruktion auseinander reissen.

Der Zug mit automatischer Richtungsänderung folgt dem Design von Akiyuky.


Nachtrag: Wir haben für das Modul Zug mit automatischer Richtungsänderung und das Riesenrad jeweils LXF Dateien für den Lego Digital Designer erstellt.

based architecture is a current hype in architecture. I am therefore not yet clear with it from the point of architecture.

I'm not clear with it

The good
It reduces the complexity in the code artifacts for a simpler maintenance.
The bad
It increases complexity of governance of the software.
The ugly
It moves the complexity of the software to the network.

The ugly

11 years ago died. Wheeler formulated one of the most important phrases for software architectures:

All problems in computer science can be solved by another level of indirection, except of course for the problem of too many indirections.

I must ask myself: what are the benefits to add the network as a layer of indirections? Handling software with networks is not trivial. The network might be not available or under heavy load. Timeouts are commonplace and many developers have never heard of the design pattern.

The bad

Governance of software is on of the most underestimated factor. In bigger systems you can't do what you want. Rules have introduced, established and must be respected. Without these rules a growing software system will collapse after a while - or maintenance costs will increase dramatically.

REST based microservice architectures are related to systems. And SOA without a strong governance will create an epic cluster fuck also.

Fine grained microservices will increase the complexity of the governance. The diagrams to visualize are increasingly confusing. And we need visualizations to get an overview and understanding of the system. And as we know, a process diagram with more than 7 boxes/tasks/whatever has the tendency to create chaos in our head.

The good

Software artifacts gets smaller. A microservice implementation should not have more than a few hundred lines of code - howsoever you measure it. This is good for refactoring or throwing the code away and write it new from scratch.

But I'm not quite sure that this is really a benefit. Do you really rewrite an implementation? In normal cases it is not a very complex tasks to refactor a code system with a few hundred lines of code. The benefit of rewriting comes in when you switch the technology stack. With microservices this is not a huge change-it-all tasks but you can change one service after the other.

More often than rewriting or refactoring a microservice (that works) is to refactor the entire system. Here REST based microservice based only on can become a pain in the ass. Refactoring a not typed software system is a mess. Also the communicating of code intention without a type system. Without a type system also design and governance (see: The bad) can become very problematic.

Although some advocates of Microservice architectures do not want to read: exports not only JSON, but also XML hedged with or any other technology that simple adds type safety.

[7 ENTEN HÄNGEN AN SPIESSEN IN EINEM FENSTER. IM HINTERGRUND SIND ASIATISCHE KÖCHE AM ARBEITEN. AUFGENOMMEN DURCH EINE SCHEIBE IN EINE RESTAURANTKÜCHE NAHE MUSEUMSINSEL (BERLIN).]
 

Find the whole code for the proof of concept on Github

A proof of concept to use the incredible JCommander API from Cédric Beust together with CDI in a Java SE environment.

The goal was to use the commands API with the @Parameters annotation together with CDIs natural plugin API Instance.

This means, a lot of sub commands with different parameters can be executed by a main command from command line. The parameters of the main command should be injected to the sub command implementation. The sub command can have own, different parameters.

An example for such command system is git.

Example


    git -c author=sascha.kohlmann@example.com commit -am "a commit"

Implementation

The main command configuration

The class with the main method must contain @Produces annotated method which returns a static variable with the only MainConfiguration instance.


    public class Application {

        private final static MainConfiguration MAIN_CONFIG = new MainConfiguration();

        @Produces @Config
        private MainConfiguration configuration() {
            return MAIN_CONFIG;
        }

        public static final void main(final String... args) {
            // do something
        }
    }    

The main method contains only the initialization of the Weld-SE container and runs the application.


    public static final void main(final String... args) {        
        final Weld weld = new Weld();
        try (final WeldContainer container = weld.initialize()) {
            result = container.select(Application.class).get().run(args);
        }
    }

    String run(final String... args) {
        // the application
    }

MainConfiguration

The MainConfiguration class is a straight forward data holder. The configuration field are annotated with @Parameter.


    public class MainConfiguration {

        @Parameter(names = "-m")
        private String main;

        public String getMain() { return main; }
    }

The sub commands

Sub commands implements a common command API like the following:


    public interface Command {
        String execute();
    }

Implementations of the command must have at least the @Parameters type annotation with the names attribute given. They may have sub command specific parameters and the parameter data of the main command.


    @Parameters(commandDescription = "Simple sub command", commandNames = "subcmd")
    public class SubCommand implements Command {

        @Inject @Config
        private MainConfiguration mainConfig;

        @Parameter(names = "-p")
        private String parameter;

        @Override
        public String execute() {
            return this.mainConfig.getMain() + this.parameter;
        }
    }

After the CDI initialization all sub command with the injection point for the MainConfiguration contains now the static instance from the main class. But the configuration is yet not initialized. So having a method with @PostConstruct annotated, using the main configuration will not work. Also using the sub command specific parameters in such a method will not work.

The JCommander initialization follows in the next step. But before, we must enhance the Application class with the CDI plugin API.

Instance<Command>

The Application class gets an injectable Ìnstance<Command> field. This field will be filled by CDI after the Weld initialization with all available Command implementations.


    public class Application {

        @Inject
        private Instance<Command> commands;     

        public static final void main(final String... args) {
            // do something
        }
    }

JCommander initialization

The run method initialize the JCommander with the following steps:

  1. Create a new JCommander instance with the static MAIN_CONFIG:
    JCommander jc = new JCommander(MAIN_CONFIG);
  2. Add all instances of private Instance commands to the JCommander instance:
    this.commands.forEach(cmd -> jc.addCommand(cmd));

Afterwards, parse the command line arguments with the JCommander instance.


    jc.parse(args);

That's it.

Execute the sub command

The last step is now to get the parsed sub command name an fetch the sub command implementation from JCommander. Then call the execute() method.


    final String parsedCommand = jc.getParsedCommand();

    for (final Map.Entry cmdEntry : jc.getCommands().entrySet()) {
        final String name = cmdEntry.getKey();
        if (name != null && name.equals(parsedCommand)) {
            ((Command) cmdEntry.getValue().getObjects().get(0)).execute();
        }
    }

Testing

Testing ist straight forward:


    @Test
    public void test_sub_command_execution() {
        Application.main("-m", "main", "subcmd", "-p", "sub");
        assertThat(Application.result, is(equalTo("mainsub")));
    }

Conclusion

Using CDI and JCommander with complex commands in a Java SE environment is quite simple. Using the CDI natural plugin API (Instance) is also very simple. Together this is a strong duo to simplify the development of Java command line tools.


Find the whole code of the proof of concept on Github.

Immer diese Kriegsrhetorik. In Paris soll der Terror ein Kriegsakt gewesen sein. Nein, es war Mord. Nichts anderes als Massenmord. Für irgend eine Sache. Unwichtig für oder gegen was. Es war Massenmord.

Oder war es vielleicht doch ein kriegerischer Akt? Ein Gegenangriff, so ekelhaft das auch sein mag? Ein Gegenangriff des IS, der sich zu den Anschlägen bekannt hat? Weil französische Flugzeuge den IS bombardieren?

Auch dann ist es egal ob es ein kriegerischer Akt war oder nicht. Auch Krieg ist Mord. Staatlich sanktionierter Mord. Keinen Deut besser.