Freitag, 21. Januar 2011

OCM Certification, Java EE 5 Enterprise Architect

Das Java EE 5 Enterprise Architect Zertifikat von Oracle ist die Fortführung der Sun Certified Enterprise Architect for Java EE 5 (SCEA 5) Zertifizierung. Der Zertifizierungspfad setzt sich aus drei Blöcken zusammen.

Der erste Block besteht aus einem Wissenstest (Multiple-Choice und Drag-and-Drop Fragen), der 64 Fragen beinhaltet und der in einem Prometric Testcenter absolviert wird.

Der zweite Testblock ist ein Assignment, eine praktische Aufgabe, bei der eine Java EE Applikation zu entwerfen ist. Die zu entwerfende Java EE Applikation ist mit UML-Diagrammen zu beschreiben. Die Basis für die praktische Aufgabe sind ein verbal beschriebenes virtuelles Geschäftsszenario, ein graphisches Domainmodell und ein Anwendungsfalldiagramm (Use-Case). Neben der Beschreibung des entworfenen Systems mit einem Klassendiagramm, Komponentendiagramm, Deploymentdiagramm und Sequenzdiagrammen sind zusätzliche Kommentare über die Anforderungen, Risiken und Risikomilderung zu verfassen. Der zweite Testblock darf erst nach dem Absolvieren des Wissenstests bearbeitet werden.

Der dritte Testblock beinhaltet ein Essay mit acht Fragen zu dem zuvor entworfenen System, das wie der Wissenstest in einem Prometric Testcenter zu absolvieren ist. Entwurfsentscheidungen, Alternativen zu dem gewählten Entwurf und die Abdeckung von nichtfunktionalen Anforderungen sind mögliche Fragestellungen. Es gilt, den Entwurf des Assignments bestmöglich zu verteidigen.

Der Wissenstest ist sehr weitläufig, sodass es von Vorteil ist, entsprechende Projekterfahrung zu haben. Bei der Vorbereitung für den Wissenstest war ich regelmäßig über die breite Streuung der Fragen überrascht. Besonders die Erfahrungen der Projekte aus der Vergangenheit haben geholfen,  die Fragestellungen fernab von Java EE 5 verstehen zu können. Beispiele: JSPs mit Delegierung zu Geschäftsobjekten (Business Objects), Servlets die Diagramme erzeugen, die JDBC-ODBC-Bridge, proprietäre MVC-Frameworks, EJB Persistenztechniken auf Basis von JDBC und ResultSets, CORBA Programmierung mit der Java IDL und Applet-Sicherheit (Sandbox-Restriktionen).

Liste (ohne den Anspruch der Vollständigkeit) für den Wissenstest:

  • OO-Prinzipien (Kapselung, Vererbung, Komposition, Kopplung, Separation of Concerns)

  • Architekturen (Client-Server-Systeme, Mehrschichtsysteme, SOA, Thin-/Thick-Clients, nichtfunktionale Anforderungen, EJB- und Web-zentierte Architekturen, Cluster, Load Balancing, Replikation) 

  • Integration und Messaging (Java EE WebServices (SOAP und REST), JCA, JMS (Queue und Topic)

  • Geschäftsschicht Technologien (Session Beans, MDBs, Entity Beans, ORM, Unterschiede der vorherigen EJB-Standards zu EJB 3.0, Programmier- und Deploymentmodelle)

  • Webschicht Technologien (JSP, Servlets, Servletfilter, JSTL, EL, JSF, AJAX)

  • Design Patterns (GoF und J2EE Patterns, Patternszenarios in unterschiedlichen Layern einer Architektur, Anwendungsfälle und Merkmale einzelner Patterns)

  • Sicherheit (Applet- und JNLP-Restriktionen der JRE Sandbox, Byte Code Verification, Web-, EJB- und WebServices Sicherheit, SSO, potentielle Sicherheitsrisiken (Attacken wie XSS, SQL-Injection, Denial of Service, Spoofing, Tampering, Phising, Man in the Middle und deren Vermeidung (Verschlüsselung, Filter, Sicherheitszertifikate, Signaturen)

  • APIs und deren Verwendung (JAX-WS, JAXB, JAXP, JAXR, SAAJ, JAX-RPC, WS-Security, JAAS, JCE, JSSE, Java IDL, JMS, JCA, JNDI, JDBC)

  • Protokolle (RMI, IIOP, JRMN, SOAP, XML over HTTP, SSL)

Die Fragestellungen des Wissenstests kombinieren Architekturansätze, nichtfunktionale Anforderungen, Programmiermodelle, Design Patterns und APIs miteinander, sodass auf Basis eines gestellten Szenarios jeweils die richtige Antwort aus Sicht des Architekten zu finden ist.

Exemplarische Fragestellungen in vereinfachter Form:

(1) Welche nichtfunktionalen Anforderungen einer Java EE Applikation werden erhöht, wenn statt eines Applikationsservers ein Cluster von Applikationsservern mit "Load Balancing" Funktionen eingesetzt wird? Lösung: Die Skalierbarkeit, Ausfallsicherheit und Verlässlichkeit der Anwendung werden erhöht.

(2) Eine Web-Applikation in der die komplette Geschäftslogik als JSP-Scriptlets programmiert wurde, hat eine schlechte Performanz. Warum ist die Performanz schlecht und wie könnte man die Performanz verbessern? Lösung: Die aus den JSP-Seiten generierten Servlets werden zur Laufzeit bei jedem Request "gelockt". Die Geschäftslogik sollte deshalb von JSP-Scriptlets zu Business Objects refactored werden.

(3) Wie kann die Gefahr einer "SQL-Injection" minimiert werden? Lösung: Durch einen Filter und Prepared Statements.

(4) Wie verwaltet man den Konversationsstatus eines Clients? Lösung: Mit einer HTTP Session oder einem Stateful Session Bean.

(5) Welches Pattern ist nützlich, um die Konstruktions- und Implementierungsdetails eines Objektes zu verbergen? Lösung: Abstract Factory.

(6) Welche Nachteile entstehen durch enge Bindung? Lösung: Die Wiederverwendung von Klassen ist schwierig und Änderungen in einer Klasse haben Änderungen in abhängigen Klassen zur Folge.

(7) Welches Design Pattern nutzen ORM-Frameworks? Lösung: Domain Store.

(8) Nenne zwei Design Patterns, die konform zu Separation of Concerns sind? Lösung: Service To Worker (trennt die Geschäftslogik von der Anzeigelogik) und Data Access Object (trennt die Geschäftslogik von der Speicherlogik).

(9) Welches Entwurfsprinzip besteht zwischen Session und Entity Beans? Lösung: Separation of Concerns.

(10) Welche Java EE Komponente hilft bei der Migration zu einer SOA? Lösung: Stateless Session Bean (kann als Web Service publiziert werden: @WebService).

(11) Welche Techniken kennzeichnen Polymorphie? Lösung: Erweitern einer Klasse und Überschreiben einer existierenden Methode. Implementieren einer Schnittstelle mit unterschiedlichen Klassen.

(12) Nenne zwei Aktionen, die ein nicht signiertes Applet ausführen kann? Lösung: Neue Threads in der JVM erzeugen und überdurchschnittlich viel Prozessorleistung nutzen.

Literatur, Mock-Tests und Online-Quellen für die Vorbereitung

  • Sun Certified Architect for Java EE Study Guide (Second Edition) von Mark Cade und Humphrey Sheil (das Buch ist einfach Klasse!)

  • Java EE 5 Tutorial

  • Mock-Tests bei Whizlabs (SCEA Exam Simulator CX 310-52)

  • ePractice bei Oracle (Java Enterprise Edition 5 Enterprise Architect Certified Master Exam)

  • SCEA Forum der JavaRanch mit Referenzen zu weiteren Informationsquellen

Die Aufzählung der Informationsquellen ist nur ein Richtungsweiser für die Vorbereitung auf die Zertifizierung. Je nach Erfahrung sind weitere Quellen zu Java EE Technologien heranzuziehen.

Ein interessanter Aspekt der Zertifizierung ist, zu einem gegebenen Geschäftsmodell die richtige Architekturentscheidung zu treffen. Nicht immer ist der EJB-zentrierte Ansatz mit EJB 3.0, JPA und JSF die richtige Lösung. Der Web-zentrierte Ansatz hat bei leichtgewichtigen Architekturen, die wenige bis keine Transaktionen und keine anderen EJB Containerdienste nutzen wollen, durchaus Vorteile.

Interessant sind die vielfältigen Integrationsszenarien, sodass Java Web Services im heterogenen Umfeld ein gutes Mittel für die Integration von Komponenten und Applikationen sind. In reinen Java-Umgebungen aber auch JMS die Nase vorne haben kann. JCA als klassische EAI-Technik ist im Legacy Umfeld mit JMS (MDBs) für Notifizierungen kombinierbar und nutzt dabei die Dienste des EJB Containers, wodurch weitere Integrationsmöglichkeiten entstehen.

Die Vielfältigkeit der Fragestellungen schafft Raum für neue Blickwinkel, Eindrücke und Ideen. In der Summe ein schöner Lohn für den Arbeitsaufwand auf dem Zertifizierungspfad zum Java EE 5 Architekten.

Mittwoch, 12. Januar 2011

Code Kata

Tai Chi Sportler führen regelmäßig Übungen zur Perfektion ihrer Bewegungsabläufe  durch. Der Bewegungsablauf ist bei den Tai Chi Übungen stilisiert und fest vorgegeben. Diese Art von Übungsform wird als Kata bezeichnet. Das häufige Wiederholen der Bewegungsabläufe bei einer Kata ist unerlässlich für den persönlichen Fortschritt eines Schülers und dient neben der Entspannung zur Vorbereitung auf einen Formwettkampf. Nur die regelmäßige Übung macht den Schüler zu einem Tai Chi Meister.

Programmierer nutzen das Konzept der Kata zur Verbesserung des Programmierstils. Die Programmierung beherrscht man nur durch ständiges Training. Eine regelmäßige Code Kata ist deshalb empfehlenswert und macht als öffentliches Code Dojo sehr viel Spass. Im Rahmen einer Diskussion des Clean Code Developer Forums über stinkenden Quellcode ist spontan ein Code Dojo entstanden.

Die Aufgabenstellung des Code Dojo war eine Code Kata mit dem Ziel einen einfachen Algorithmus, der eine arabische Zahl in eine römische Zahl konvertiert, zu refaktorisieren Der Ursprungsalgorithmus in der Java Notation umfasst folgende Implementierung:
public class RomanNumerals {
    
  static int[] nums = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
  static String[] rum = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX",
                          "V", "IV", "I" };

   public static string toRoman(int number) {
    
      String value = "";
      for (int i = 0; i < nums.length && number != 0; i++) {    
          while (number >= nums[i]) {
              number -= nums[i];
              value += rum[i];
          }
      }
    
      return value;
   }
} 
Die ersten Refactorings haben den Algorithmus auf die Leserlichkeit hin verbessert. Kleinere Methoden wurden konform den CCD-Prinzipien geschrieben, um den Lesefluss zu erhöhen. Das Single Level of Abstraction (SLA) Prinzip wurde dabei partiell verletzt. Relativ schnell erkannte man, dass die beiden Arrays zu fehleranfällig sind. Die Array-Elemente müssen in einer definierten Ordnung vorliegen und die Arrays könnten unabhängig voneinander weitere Elemente aufnehmen.

Erweiterte Implementierungen wie Value Objects, die die konvertierte römische Zahl speichern, ein selbständiges Mapping-Objekt und andere Implementierungen sind diskutiert worden. Damit das Refactoring stattfinden konnte und damit die Pfadfinderregel überhaupt angewendet werden kann, sind zunächst eine Reihe von Unit-Tests geschrieben worden.

Die Teilnehmer der Code Kata waren nach den ersten Implementierungen noch nicht mit den Ergebnissen des Refactorings zufrieden. Der einfache Konvertierungsalgorithmus wurde mit dem Fortschritt des Refactorings durch eindeutige Bezeichner zwar lesbarer, auf der anderen Seite blähte sich der Quellcode auf. Teilweise hat sich der Quellcode sogar verfünfacht. Die Balance zwischen der Lesbarkeit und Einfachheit der Implementierung war noch nicht gegeben. Ein Teilnehmer hat die beiden Arrays durch ein Mapping-Objekt ersetzt, sodass die Zuordnung einer arabischen Ziffer zu einer römischen Ziffer gewährleistet ist. Das Mapping-Objekt wurde dabei wiederum in einem Array verwaltet. Das Array fungierte dabei als ein Dictionary. Eine naheligende Idee war deshalb basierend auf dem Dictionary Gedanken eine geradlinige Java API-Lösung zu implementieren.

API-Lösung:
import java.util.LinkedHashMap;
import java.util.Map;

public class RomanNumber {

 private static Map<String, Integer> mappings = new LinkedHashMap<String, Integer>();
 static {
            
     mappings.put("M", 1000);
     mappings.put("CM", 900);
     mappings.put("D", 500);
     mappings.put("CD", 400);
     mappings.put("C", 100);
     mappings.put("XC", 90);
     mappings.put("L", 50);
     mappings.put("XL", 40);
     mappings.put("X", 10);
     mappings.put("IX", 9);
     mappings.put("V", 5);
     mappings.put("IV", 4);
     mappings.put("I", 1);
 }
        
 public static String arabicToRoman(int arabicNumber) {
    
     int arabicNumberRemainder = arabicNumber;
     final StringBuilder romanNumber = new StringBuilder();
        
     for (Map.Entry<String, Integer> mapping : mappings.entrySet()) {
            
        while(arabicNumberRemainder >= mapping.getValue()) {

              arabicNumberRemainder -= mapping.getValue();
              romanNumber.append(mapping.getKey());
         }
     }
        
     return romanNumber.toString();
  }
}
Eine LinkedHashMap bietet sich als Dictionary für das Mapping der Ziffern an. Die LinkedHashMap hält die Einfügeordnung aufrecht und garantiert damit, dass der Konvertierungsalgorithmus funktioniert. Die API-Lösung nutzt hauptsächlich das Mapping der Ziffern und ist deshalb hinsichtlich der Erweiterbarkeit sicherer als die Array-Variante. Grundsätzlich sind Lösungen, die auf einer Datenstruktur basieren dehnfähiger als Lösungen, die ausgefeilte Algorithmen verwenden. Das ist sicherlich bei dem hier vorliegenden einfachen Softwarebaustein kein Argument, kann sich aber bei umfangreicheren Softwarebausteinen durchaus auszahlen.

Die innere Struktur der Lösung konnte mit einer Abstraktion verbessert werden. Die Abstraktion erlaubt es darüber hinaus auf Basis der Implementierung weitere Konvertierungsalgorithmen zu implementieren.

Abstraktion der API-Variante:
import java.util.Map; 

abstract class NumberConverter {
  
  abstract Map<String, Number> convertMappings();
  abstract String convert(final Map<String, Number> mappings, final Number number);
  
  String convertNumber(final Number number) {  
   
     return convert(convertMappings(), number);
  }
}
Die Abstraktion wendet das Template Method Pattern an. Die überschriebenen Methoden in einer Ableitung der Abstraktion bestimmen, welche Konvertierungsdaten und welcher Konvertierungsalgorithmus für die Konvertierung verwendet wird. Durch diese Implementierung wird innere Flexibilität erreicht, sodass in der Folge unterschiedliche Ausprägungen von Konvertierungen stattfinden können.

Implementierung der API-Variante:
import java.util.LinkedHashMap;
import java.util.Map;

public final class RomanNumber extends NumberConverter {

  public static String arabicToRoman(int number) {

     return new RomanNumber().convertNumber(number);
  }

  private RomanNumber() {/* prevents instantiation */}

  @Override
  Map<String, Number> convertMappings() {
    
     final Map<String, Number> mappings = new LinkedHashMap<String, Number>();
    
     mappings.put("M", 1000);
     mappings.put("CM", 900);
     mappings.put("D", 500);
     mappings.put("CD", 400);
     mappings.put("C", 100);
     mappings.put("XC", 90);
     mappings.put("L", 50);
     mappings.put("XL", 40);
     mappings.put("X", 10);
     mappings.put("IX", 9);
     mappings.put("V", 5);
     mappings.put("IV", 4);
     mappings.put("I", 1);
    
     return mappings;
  }
 
  @Override
  String convert(final Map<String, Number> mappings, final Number number) {

     int numberRemainder = number.intValue();
     final StringBuilder convertedNumber = new StringBuilder();

     for (Map.Entry<String, Number> mapping : mappings.entrySet()) {

         while(numberRemainder >= mapping.getValue().intValue()) {

             numberRemainder -= mapping.getValue().intValue();
             convertedNumber.append(mapping.getKey());
         }
     }

     return convertedNumber.toString();
  }
} 
Unit-Test der API-Variante:
import static org.junit.Assert.assertEquals;

import java.util.HashMap;
import java.util.Map;

import org.junit.Before;
import org.junit.Test;

public class RomanNumberTest {

   private Map<String, Integer> mappings = new HashMap<String, Integer>();

   @Before
   public void setUp() {

      mappings.put("", 0);
      mappings.put("I", 1);
      mappings.put("II", 2);
      mappings.put("III", 3);
      mappings.put("IV", 4);
      mappings.put("V", 5);
      mappings.put("VI", 6);
      mappings.put("VIII", 8);
      mappings.put("IX", 9);
      mappings.put("X", 10);
      mappings.put("XI", 11);
      mappings.put("XL", 40);
      mappings.put("L", 50);
      mappings.put("LXXX", 80);
      mappings.put("XC", 90);
      mappings.put("C", 100);
      mappings.put("D", 500);
      mappings.put("CMXCIX", 999);
      mappings.put("M", 1000);
      mappings.put("MI", 1001);
      mappings.put("MDCCCLXXVIII", 1878);
      mappings.put("MCMLIII", 1953);
      mappings.put("MCMLXXXIV", 1984);
      mappings.put("MMM", 3000);
      mappings.put("MMMMMM", 6000);
      mappings.put("MMMMMMMMMCMXCIX", 9999);
      mappings.put("MMMMMMMMMM", 10000);
      mappings.put("MMMMMMMMMMI", 10001);
   }

   @Test
   public void testArabicToRomanNumberConvertion() {

      for(Map.Entry<String, Integer> mapping : mappings.entrySet()) {

         assertEquals(mapping.getKey(), 
                      RomanNumber.arabicToRoman(mapping.getValue()));
      }
   }
}
Die Implementierung der Klasse "RomanNumber" ist durch Vererbung nicht erweiterbar und kann aufgrund des privaten Konstruktors nicht instanziiert werden. Der einzige Zugang zu der Klasse ist die Methode "arabicToRoman". Die Verriegelung ist notwendig, damit die Klasse nicht durch Instanziierung oder Vererbung gebrochen wird.

Eine Performanzbetrachtung wurde bei der Implementierung der API-Variante nicht durchgeführt. Eine deutliche Optimierung könnte durch das einmalige Vorhalten der Konvertierungsdaten erreicht werden. Keine klar definierten, nichtfunktionalen Anforderungen ergeben unterschiedliche Lösungen. Bei der Code Kata ist der Verwender des Softwarebausteins und dessen Anforderungen nicht benannt worden, deshalb sind viele kreative und rein funktional korrekte Implementierungen entstanden.

Tipp: Bei Softwarebausteinen, die produktiv eingesetzt werden, sind der Verwender des Softwarebausteins und dessen Anforderungen die treibenden Kräfte. Ein Softwarebaustein sollte deshalb immer aus Sicht des Verwenders implementiert werden.

Die Code Kata hat verdeutlicht, dass viele Wege zum Ziel führen und je nach Implementierung die eine oder andere Lösung die Nase vorn hat. Eine Kata in einem Code Dojo ist unabhängig  von der Qualität der gefundenen Lösungen ein gutes Mittel, um sich mit anderen Entwicklern auszutauschen und dabei seinen eigenen Programmierstil zu verbessern.


Der Rechtshinweis des Java Blog für Clean Code Developer ist bei der Verwendung und Weiterentwicklung des Quellcodes des Blogeintrages zu beachten.

Sonntag, 9. Januar 2011

Software complexity by example

Die Entwicklung von Software wird hauptsächlich von fachlichen Anforderungen getrieben. Der fachliche Nutzen einer Software ist dabei wesentlich für die Benutzerakzeptanz eines Softwareproduktes. Die Benutzerfreundlichkeit im Kontext der nicht funktionalen Anforderungen erhöht die Komplexität einer Software. Das Datenvolumen beeinflusst stark die Antwortzeiten einer Applikation. und ist deshalb eng mit der Benutzerakzeptanz verbunden. Die Stabilität einer Applikation und die Verlässlichkeit spielen eine wichtige Rolle für die Benutzerakzeptanz und den Erfolg eines Softwareproduktes.

Eine fachliche Funktionalität ist bei schlechter Antwortzeit und/oder Stabilität nahezu wertlos und ein Ärgernis für die Mitarbeiter der Fachabteilung. Das Spannungsfeld zwischen der Softwareentwicklung und der Fachabteilung kann dabei zum Schmelztiegel werden. Wie die Komplexität eines einfachen Dialogbeispiels bereits den Tiegel aufheizt, versucht dieser Artikel zu erläutern.

Beschreibung des Dialogbeispiels:

Das Beispiel beinhaltet einen Dialog zum Anzeigen und Quittieren von Alarmmeldungen. 

Folgende fachliche Funktionalitäten bietet der Dialog:

  • Laden einer Alarmmenge
  • Anzeigen des Ladezustandes mit einem Fortschrittsbalken
  • Anzeigen der Alarme in einem Listenfeld (Listbox) mit einem Renderer
  • Filtermöglichkeit zur Reduzierung der Alarmmenge
  • Speicherung des Filters zur schnellen Anzeige einer Alarmmenge
  • Anzeige und Quittiermöglichkeit für einen selektierten Alarm

Beschreibung weiterer Anforderungen:

Der Dialog soll jederzeit geschlossen werden können. Der aktuelle Ladezustand spielt dabei keine Rolle.  Die Benutzeroberfläche des Dialoges darf nicht einfrieren. Die Interaktionsmöglichkeiten des Benutzers sollen reibungslos zu jedem beliebigen Zeitpunkt durchführbar sein. Der Dialog darf die Benutzeroberfläche der zugrundeliegenden Applikation nicht beeinträchtigen. Im Hintergrund eingehende Alarmmeldungen sollen verarbeitet und angezeigt werden. Der Dialog soll für beliebige Services zur Anzeige der Alarmmeldungen aufschaltbar sein.

Tipp: Bei der Programmierung von Benutzeroberflächen sollte stets nach dem Kernprinzip Separation of Concerns implementiert werden. Es lohnt sich deshalb das Command Pattern einzusetzen, weil die Aktionen in einer Benutzeroberfläche über Menüs, die Werkzeugleiste (Toolbar) und Hot-Keys ausgelöst werden können. Die Anwendung des Command Patterns ist eine wesentliche Voraussetzung für die Einhaltung des DRY-Prinzips. Die Möglichkeiten von Java Generics in Kombination mit einer Ellipse, erlauben es, parametrisierbare Kommandos anzuwenden, sodass einer lose gekoppelten und erweiterbaren Implementierung nichts mehr im Wege steht. Die Abhängigkeiten zwischen den aktionsauslösenden Elementen der Benutzeroberfläche sind mit einem Mediator und/oder Visitor synchronisierbar. Der Status eines Menüeintrages ist auf diese Art und Weise mit dem Status einer Schaltfläche der Werkzeugleiste abgleichbar.

Erste Hürde - Anzeigen des Ladezustandes

Der Fortschrittsbalken zeigt beim Ladevorgang für eine beliebige Menge von Alarmmeldungen den Ladezustand an. Das sieht nach einem mathematischen Problem aus. Die variable Menge der Alarmmeldungen stellt hierbei die erste Hürde dar. Das Problem ist mit einem einfachen Dreisatz nicht zu lösen. Der Dreisatz gibt allerdings die Richtung der Problemlösung vor. Mehr soll an dieser Stelle nicht verraten werden. Eine kleine Rechenaufgabe vor dem Weiterlesen beugt der Langeweile vor.

Ladezustand anzeigen

Zweite Hürde - Alarmmenge laden

In dem Dialog wird über ein Business Delegate auf die Session Facade der Serverapplikation zum Laden der Alarmmenge zugegriffen. Der Aufruf zwischen dem Business Delegate und der Session Facade erfolgt synchron. Die Benutzeroberfläche blockiert deshalb während dem Laden der Alarmmenge.

Eine brauchbare Lösung für das Problem ist, die Alarmmenge in kleineren Teilmengen in einem Hintergrundthread zu laden. Durch diese Variante kann der Ladevorgang unterbrochen werden und die Benutzeroberfläche friert nicht ein. In Java Swing Applikationen bietet sich der in Java SE 6 integrierte Swing Worker zur Problemlösung an. Der Swing Worker startet einen Hintergrundthread, der unterbrechbar ist und bietet darüber hinaus die Möglichkeit an, die Daten nach der Ladeoperation auszulesen, um anschließend die Benutzeroberfläche zu initialisieren.

Alarmmenge anzeigen

Anmerkung: Die in dem Dialog angezeigten Alarme sind mit einem Unit-Test erzeugt worden und haben keinen fachlichen Anspruch.

Die Anzeige der Icons in dem Listenfeld ist keine Standardfunktionalität. Für die Icon-Darstellung ist ein spezieller Renderer zu implementieren. Das Listenfeld wird initialisiert, nachdem der Hintergrundthread des Swing Workers seine Arbeit erledigt hat. Die Anwendung des Swing Workers in GUI-Applikationen ist ratsam. Dem Event Dispatch Thread (EDT) des Swing GUI-Systems sollte man nicht in die Quere kommen, weil sich dabei Refresh-Probleme ergeben können. Refresh-Probleme sind neben dem Einfrieren der Benutzeroberflächen ein weiteres Problem, das bei der GUI-Programmierung zu vermeiden ist.

Dritte Hürde - Alarmmenge filtern

Das Listenfeld verwaltet die Alarmmenge in einem eigenen Datenmodell. Die Alarmmeldungen werden als  eine Collection von Data Transfer Objects (DTOs) über das Business Delegate geladen und im Datenmodell des Listenfeldes verwaltet. Zur Filterung der Modelldaten reicht das einfache Modell des Listenfeldes nicht aus. Das Modell des Listenfeldes ist deshalb um die Filterfunktionalität erweitert worden. Dem Filtermodell liegt eine Model View Controller (MVC) Struktur zugrunde, sodass das Filtermodell in der Folge erweiterbar ist.

Alarmmenge filtern
Der Alarmfilter reagiert bei der der Eingabe eines Suchstrings in dem Filtereingabefeld. Gibt man ein einfaches "q" ein, werden alle Alarme angezeigt die bereits quittiert worden sind. Der Alarmfilter ist speicherbar, sodass dieser ohne Texteingabe ausgelöst werden kann.

Das einfache Dialogbeispiel veranschaulicht, warum die Entwicklung von Softwareprodukten komplex ist. Die Balance zwischen den fachlichen Anforderungen eines Softwareproduktes und den nicht funktionalen Anforderungen ist häufig schwierig. Manchmal ist es eine Gratwanderung große Datenmengen zu verarbeiten und dabei die Benutzerakzeptanz aufrecht zu erhalten. 

Der Dialog ist nur ein sehr kleiner Teil einer komplexen Java EE 6 Anwendung, die Daten im Hintergrund verarbeitet, selbst bei hoher Last auf Benutzerinteraktionen reagiert und keine Refresh-Probleme aufweist. Das solche Applikationen und deren Benutzeroberflächen nicht mit einem "Single Thread Model" umsetzbar sind, dürfte klar sein. Parallele Threads in Benutzeroberflächen zu synchronisieren, ohne dem EDT in die Quere zu kommen, keine Deadlocks zu verursachen und die Performanz auszubremsen, sind Herausforderungen, die es bei der Programmierung von Benutzeroberflächen zu meistern gilt. Wie man Synchronisationsprobleme in Benutzeroberflächen löst ist nicht Gegenstand des Artikels, aber eine der wesentlichen Herausforderungen bei der Programmierung von interaktiven Benutzeroberflächen.

Wenn ein einzelner Dialog einer Anwendung offensichtlich bereits eine nicht zu unterschätzende Komplexität besitzt, lässt sich der Schluss ziehen, dass die Entwicklung von Softwareprodukten eine komplexe Angelegenheit ist.

Montag, 3. Januar 2011

Autonomic computing grip for SOA

Serviceorientierte Anwendungen setzen sich aus Services zusammen, die eine hohe Kohäsion aufweisen. Best Practices, wie beispielsweise die Kapselung und generische Programmiermethoden, erlauben es, Services als allgemeine, wiederverwendbare Komponenten auszulegen. SOA-Architekturen sind lose gekoppelt und orchestrierbar. 

Die Evolution von monolithischen Systemen zu serviceorientierten Architekturen basiert auf der Erfahrung bei der Entwicklung und dem Betrieb von komplexen Softwaresystemen, bei der sich lose gekoppelte Systeme durchgesetzt haben. Die lose Koppelung wurde durch die Möglichkeiten der Messaging-Systeme (MOM) populär. Messaging-Systeme und klassische Hub-and-Spoke sowie Message Broker Architekturen zeichnen sich durch eine hohe Verfügbarkeit, Skalierbarkeit, asynchrone Kommunikation und sehr hohe Flexibilität durch Routingtabellen und standardisierte Datentransformationen aus.

Der Java EE Standard unterstützt optimal die Anbindung an Messaging-Systeme mit Message Driven Beans und der JMS-API. Die Anwendung von Messaging-Techniken ist dabei nicht nur auf die Applikationsentwicklung begrenzt, sondern wird häufig in Integrationsszenarien eingesetzt. Die Integration von komplexen Softwaresystemen bringt neue Herausforderungen mit sich, sodass die Vorteile von Messaging Systemen nicht ausreichend sind um Integrationsszenarien lösen zu können. Im Bereich der Integration von Softwaresystemen und dem Enterprise Application Integration (EAI) sind deshalb auch die Komponenten in ihrer Struktur flexibel ausgelegt. Die Flexibilität wird dort durch klar definierte Schnittstellen mit der Möglichkeit zur Adaptivität, der Unabhängigkeit von Protokollen (Protokolltransformationen), der Komposition  und Orchestrierung (BPMN / BPEL) erreicht.

Beim Technologieschritt vom Message Broker zum Enterprise Service Bus (ESB) haben die Hersteller von SOA-Entwicklungswerkzeugen große Fortschritte erzielt. Integrationsszenarien sind dabei unabhängig von ihrer Komplexität, ohne eine Zeile Programmcode schreiben zu müssen, lösbar. Graphische Werkzeuge und die Normierung der Prozessdarstellungen (BPMN 2) erlaubt es, komplexe Geschäftsanforderungen mit Zeitabhängigkeiten, Parallelität und Verzweigungen zu modellieren. Ein in der Designphase erstelltes Modell bildet dabei die Basis für die automatisierte Generierung der Serviceartefakte und dem Deployment in der ESB Umgebung.

Die neue Generation von Werkzeugen verschiebt den Schwerpunkt von der Erstellung einer Applikation in Richtung Wartung und Erfordernissen des Betriebes. Die Verlagerung des Schwerpunktes wird erst durch die Reduzierung des Programmieraufwandes möglich, sodass mehr Zeit für die strategische Inbetriebnahme eines Softwareproduktes vorhanden ist. Die Hersteller von Softwareprodukten haben diesen Trend erkannt und  mit der Common Event Infrastructure (CEI) einen standardisierten Layer definiert.

Der Nachrichtenfluss im CEI-Layer basiert auf dem Common Base Event (CBE) Format.  Ein Nachrichtenfluss in einer CEI-Umgebung besteht aus Informationsmeldungen und Meldungen, die durch Fehlerszenarien produziert werden. Diese Meldungen fungieren als Ereignisse, die zeitnah bearbeitet und analysiert werden müssen, um den reibungslosen Betrieb einer Unternehmensanwendung sicherzustellen.

In der Eclipse Test & Performance Tools Platform (Eclipse TPTP) ist der Hyades-Framework integriert, der das Common Base Event Format nutzt. Strukturierte Detailinformationen eines Services, mit nach Kategorien angelegten Detailinformationen, eignen sich zur gezielten Analyse von Ereignismeldungen. Anders als bei herkömmlichen Trace-Frameworks wird ein standardisiertes und bereits in vielen Werkzeugen integriertes Format zum Austausch der Ereignismeldungen verwendet.

Eine CEI-Infrastruktur beinhaltet sowohl Ereigniserzeuger, die Services einer serviceorientierten Architektur und Infrastrukturkomponenten (Applikationsserver, Message Broker, ESB) als auch Ereignisempfänger, die Werkzeuge zum Auswerten der Ereigniskette. Zur Auswertung sind Analysemöglichkeiten mit Filtern und Navigationsmöglichkeiten in der Ereigniskette nötig, um Fehlerszenarien detailiert auswerten und bewerten zu können. Ohne Analysemöglichkeiten sind Fehlerbilder nur sehr schwer aufzubauen und Wiederholungsfehler kaum zu vermeiden.

Die CEI-Umgebung ist Teil des Autonomic Computings einem Paradigma das neben der Analyse von Nachrichtenflüssen weitergehende Funktionalitäten wie Selbstkonfiguration, Selbstmanagement und automatisierte Optimierungen beinhaltet.

Der Service Manager 2.0 ist eine Komposition von Applikationen, die zur Auswertung der  Ereigniskette in einer CEI-Umgebung eingesetzt werden kann. Der Service Manager 2.0 stellt deshalb eine interessante Möglichkeit dar fehlerhaftes Verhalten zeitnah analysieren und auswerten zu können. Die Trennung des Monitorings der Services und damit verbunden schnellere Reaktionszeiten im Fehlerfall, sowie das Analysewerkzeug für die nachträgliche Analyse einer Fehlerkette, erlaubt  gezielt Maßnahmen zum richtigen Zeitpunkt zu treffen.

Interessiert am Service Manager 2.0?!

Informationen zum Common Base Event Format

Das Common Base Event Format definiert die Struktur von Ereignissen, die von verschiedenen Applikationen erzeugt werden, in einem einheitlichen, gemeinsamen Datenformat. Dieses Format wird von  verteilten Applikationen zum Logging, Management und Problemerkennung verwendet, um eine standardisierte Auswertung der darin enthaltenen Informationen zu ermöglichen. Ausgetauscht werden sowohl technische als auch fachliche Informationen. Mit der Zusammenführung von technischen und fachlichen Daten lässt sich eine Vielzahl von Funktionen automatisieren.