Schon seit ein paar Tagen habe ich mich mit Drools beschäftigt. Jetzt endlich kann ich sagen, die Engine, die ich fürs Monitoring benutzen kann. Was habe ich also die letzten Tage gemacht?
Zuerst einmal findet man im Netz relativ viel Material zu Drools. Die Beispiele für Regeldefinitionen haben mich natürlich am meisten interessiert. Schnell hatte ich einige gefunden, die ganz gut aussahen. Daher begann ich mich näher mit Drools zu beschäftigen um ein kleines Hello-World-Projekt aufzusetzen. Damit fingen die Probleme an.
Nachdem ich alle Ressourcen heruntergeladen und eingebunden hatte, habe ich ein Rule-File nach den Beispielen im Netz geschrieben. Leider lief nichts. Bei der Fehlersuche verwirrte mich Anfangs, dass es noch so viele andere Sprachen für Drools gab. Das genau ist der Punkt!
Drools hat erstens sein eigenes Regelformat namens "drl" (kein XML) und zweitens unterstützt es außerdem noch Regeldefinition via XML. Das Tückische daran ist, dass Drools, aktuell in der Version 5.2.0 vorliegend, eine sehr starke Entwicklung durchlaufen hat. So gibt es einige verschiedene XML-Formate, die alle nicht mehr aktuell sind. Die Materialien, die man im Netz dazu findet, sind oft für die alten Formate gewesen. Wenn man das weiß, stellt es kein Problem dar :-)
Mein Hello-World-Beispiel habe ich zum laufen bekommen. Es ist das Ergebnis dieses Wochenendes. Eine komische Fehlermeldung wird jedoch nach wie vor angezeigt. Trage ich die Schemaversionen analog zum Versionsstand (5) von Drools ein, findet er das Schema nicht. Trage ich die Version 4 ein, wie es in der aktuellen Dokumentation von der Drools-Seite zu lesen ist, bekomme ich die Meldung, dass ich doch bitte mal Version 5 eintragen soll. Seltsam!
Mein Hello-World-Beispiel kommt später.
Montag, 11. Juli 2011
Auswahl einer Rule-Engine
Um Business-Logik, also z.B. die Implementierung der SLAs, zu kapseln, kann man Rule-Engines verwenden. Dafür wird die Logik in Regeln (in einer speziellen Sprache) definiert. Vorteile sind:
Prozesse oder Daten müssen auf bestimmte Eigenschaften ausgewertet werden. Wird eine bestimmte Bedingung erfüllt, muss eine dafür geplante Aktion ausgeführt werden.
Diese Sachverhalte kann man in Regeln formulieren. Unsere Regeln bestehen also aus:
Implementierung von Rule-Engines für Java gibt es einige (Vgl. http://java-source.net/open-source/rule-engines). Das Problem bei der Auswahl ist die Sprache, mit der die Regeln verwendet werden. Aktuell gibt es noch nicht wirklich einen Standard für solche Sprachen. Es gibt Sprachen, mit XML-Syntax, mit Lisp-ähnlicher Syntax, und diverse andere DSLs (Mehr Interessantes zu DSLs auf: http://raik-bieniek.blogspot.com/).
Bei der Suche nach einer geeigneten Rule-Engine für das Monitoring ist also die Regel-Sprache wichtig. als Regelsprache werde ich eine XML-Sprache verwenden. Die Manipulation von XML ist sehr einfach, da es für XML genügend Werkzeuge dafür gibt. In wie weit es genügend gute Werkzeuge für proprietäre Sprachen gibt, ist mir nicht bekannt. Das Suchen danach liegt momentan nicht in meinem Fokus. Daher soll es XML sein.
Weiterhin ist es von Vorteil, wenn die Rule-Engine für OSGi geeignet ist, sprich es sollte eine OSGi-Version davon geben. Dies ist jedoch kein "Muss", mehr ein "Nice-To-Have".
- Der Code ist leichter verständlicher. Die Regeln sind in einem extra Dokument, von wo aus man zentral alle Regeln bearbeiten/betrachten kann.
- Es erfolgt eine bessere Trennung von Daten und Logik.
- Auch bei großen Datenmengen können die Business-Rules noch schnell ausgeführt bzw. die Daten noch schnell ausgewertet werden.
- Die Regeln können an aktuelle Anforderungen angepasst werden, ohne das System bis ins Detail kennen zu müssen ... und (!) man kann die Regeln von Außen zur Laufzeit gut manipulieren.
Prozesse oder Daten müssen auf bestimmte Eigenschaften ausgewertet werden. Wird eine bestimmte Bedingung erfüllt, muss eine dafür geplante Aktion ausgeführt werden.
Diese Sachverhalte kann man in Regeln formulieren. Unsere Regeln bestehen also aus:
- einer Bedingung, auf die ein Eingabedatum geprüft werden muss
- und ein Folgeaktion, die nur dann ausgeführt wird, wenn die Bedingung erfüllt worden ist.
Implementierung von Rule-Engines für Java gibt es einige (Vgl. http://java-source.net/open-source/rule-engines). Das Problem bei der Auswahl ist die Sprache, mit der die Regeln verwendet werden. Aktuell gibt es noch nicht wirklich einen Standard für solche Sprachen. Es gibt Sprachen, mit XML-Syntax, mit Lisp-ähnlicher Syntax, und diverse andere DSLs (Mehr Interessantes zu DSLs auf: http://raik-bieniek.blogspot.com/).
Bei der Suche nach einer geeigneten Rule-Engine für das Monitoring ist also die Regel-Sprache wichtig. als Regelsprache werde ich eine XML-Sprache verwenden. Die Manipulation von XML ist sehr einfach, da es für XML genügend Werkzeuge dafür gibt. In wie weit es genügend gute Werkzeuge für proprietäre Sprachen gibt, ist mir nicht bekannt. Das Suchen danach liegt momentan nicht in meinem Fokus. Daher soll es XML sein.
Weiterhin ist es von Vorteil, wenn die Rule-Engine für OSGi geeignet ist, sprich es sollte eine OSGi-Version davon geben. Dies ist jedoch kein "Muss", mehr ein "Nice-To-Have".
Freitag, 17. Juni 2011
Service Level Agreements - wir brauchen Monitoring
Als nächste Etappe für den HTS steht eine weitere Komponente für die HTI an. Um den HTS tatsächlich einem Kunden als Dienst anbieten zu können, müssen bestimmte Dinge gewährleistet werden können:
Damit die HTI überhaupt sicherstellen kann, dass bestimmte Dienstleistungen innerhalb einer definierten Zeit erbracht werden können, benötigt sie eine Monitoring-Komponente.
Monitoring bezeichnet, grob gesagt folgendes:
- Es wird ein Dienst mit einer bestimmten Leistung erbracht,
- und er wird innerhalb einer gewissen Zeit erbracht.
Damit die HTI überhaupt sicherstellen kann, dass bestimmte Dienstleistungen innerhalb einer definierten Zeit erbracht werden können, benötigt sie eine Monitoring-Komponente.
Monitoring bezeichnet, grob gesagt folgendes:
- Es werden Prozesse beobachtet bzw. Daten ausgewertet, die zu nutzbaren Informationen verarbeitet werden. Statistiken können darüber geführt werden.
- Aus solchen Informationen wird versucht weiteres Wissen über den Prozess zu erlangen. Mit Hilfe von Trends kann man weiterhin versuchen Dinge vorauszusagen. Dass vorausgesagte Ereignisse tatsächlich eintreffen, kann natürlich nicht gewährleistet werden.
- Die Beobachtung erfolgt in "Echtzeit". Dies ist ein Hauptmerkmal des Monitorings.
Hyperjaxb3 works
Die Umstellung der HTI auf ein Klassenmodell, das völlig selbständig mittels Maven, JAXB und dem Hyperjaxb3-Plugin erzeugt wird, ist geglückt. Nun braucht lediglich eine Änderung am Schema vorgenommen werden, und alle Änderungen sind sofort in den Modellklassen sichtbar. Dadurch, dass Hyperjaxb3 erlaubt, JPA-Konfigurationen in einem Custom Binding, JAXB bei der Übersetzung in Javaklassen mitzugeben, sind die JPA-Annotationen auch mit in den Modellklassen vorhanden.
Die Konsequenz ist, dass unsere Entityklassen bzw. das Konzept der parallelen Klassenhierarchie und das Mapping mit Dozer wieder überflüssig geworden ist. Da es bei jeder Änderung am Modell zu Problemen mit Dozer gekommen war, machte es das Entwickeln nicht gerade bequem.
Die Konsequenz ist, dass unsere Entityklassen bzw. das Konzept der parallelen Klassenhierarchie und das Mapping mit Dozer wieder überflüssig geworden ist. Da es bei jeder Änderung am Modell zu Problemen mit Dozer gekommen war, machte es das Entwickeln nicht gerade bequem.
Donnerstag, 9. Juni 2011
Hyperjaxb3
In einem früheren Post hatte ich bereits über die Möglichkeiten der Generierung von Javaklassen aus XML und die Beschränkungen von JAXB berichtet. Zu diesem Zeitpunkt hatte ich nach alternativen gesucht, wobei ich schon über Hyperjaxb3 gestoßen war. Auf den ersten Blick schien dieses Framework keine mögliche Alternative bzw. Erweiterung zu bieten. Die Seite http://xircles.codehaus.org/projects/hyperjaxb3 war nicht wirklich aussagekräftig.
Vor einigen Wochen haben wir begonnen unser Projekt auf Maven umzustellen. Während dieser Zeit fanden viele Änderungen an den Interna der HTI statt, was zu vielen Fehlern führte. Oft war Dozer und unsere parallele Klassenhierarchie das Problem. Für den Zweck, dass man unterschiedliche Schichten oder Komponenten mit unterschiedlichen Domain-Klassen in einem System hat, ist es absolut sinnvoll Dozer als Mapper zu verwenden. Das Prinzip von information hiding ist es nur notwendige Informationen bekannt zu geben. Alles was nicht im Rahmen der Abarbeitung einer bestimmten Aufgabe liegt, ist geheim zu halten und sollte die entsprechende Schicht oder die Komponente nicht verlassen. Pro Schicht ein eigenes Domain-Modell zu haben, ist ganz im Sinne dieses Prinzips.
In unserem Fall gibt es kaum etwas zu verbergen. Einzig das Problem der Erhaltung der Persistenzkonfiguration, bei einer erneuten Generierung des Modells, war der Grund für die parallele Klassenhierarchie und den folglich notwendigen Mapper, Dozer, zu verwenden.
Daher haben wir nochmals recherchiert, ob es denn nicht noch andere Möglichkeiten gibt und sind durch das hinzugenommene Maven nochmals auf Hyperjaxb3 gestoßen. Diesmal haben wir eine andere Projektseite (http://confluence.highsource.org/display/HJ3/Home) mit recht guten Tutorials und mit Maven-Konfigurationen gefunden.
Der Mehrwert der Verwendung von JAXB mit Hyperjab3-Plugin ist enorm:
Die vollständige Migration der Alternative in das Produktivsystem ist in Arbeit und es bleibt abzuwarten in wie weit alles gut geht.
Vor einigen Wochen haben wir begonnen unser Projekt auf Maven umzustellen. Während dieser Zeit fanden viele Änderungen an den Interna der HTI statt, was zu vielen Fehlern führte. Oft war Dozer und unsere parallele Klassenhierarchie das Problem. Für den Zweck, dass man unterschiedliche Schichten oder Komponenten mit unterschiedlichen Domain-Klassen in einem System hat, ist es absolut sinnvoll Dozer als Mapper zu verwenden. Das Prinzip von information hiding ist es nur notwendige Informationen bekannt zu geben. Alles was nicht im Rahmen der Abarbeitung einer bestimmten Aufgabe liegt, ist geheim zu halten und sollte die entsprechende Schicht oder die Komponente nicht verlassen. Pro Schicht ein eigenes Domain-Modell zu haben, ist ganz im Sinne dieses Prinzips.
In unserem Fall gibt es kaum etwas zu verbergen. Einzig das Problem der Erhaltung der Persistenzkonfiguration, bei einer erneuten Generierung des Modells, war der Grund für die parallele Klassenhierarchie und den folglich notwendigen Mapper, Dozer, zu verwenden.
Daher haben wir nochmals recherchiert, ob es denn nicht noch andere Möglichkeiten gibt und sind durch das hinzugenommene Maven nochmals auf Hyperjaxb3 gestoßen. Diesmal haben wir eine andere Projektseite (http://confluence.highsource.org/display/HJ3/Home) mit recht guten Tutorials und mit Maven-Konfigurationen gefunden.
Der Mehrwert der Verwendung von JAXB mit Hyperjab3-Plugin ist enorm:
- Die Klassen des Domain-Modells werden bei jedem Buildvorgang mit erzeugt.
- Diese enthalten nun sogar die Persistenzkonfiguration (in Form von JPA-Annotationen).
- Daher wird die zweite Klassenschicht (unsere bisher als Entities bezeichneten Klassen) und folglich Dozer als Mapper überflüssig.
Die vollständige Migration der Alternative in das Produktivsystem ist in Arbeit und es bleibt abzuwarten in wie weit alles gut geht.
Dienstag, 12. April 2011
Bug in JPA beim Umgang mit leeren Listen
In den letzten Tagen haben wir ein wenig mit JPA und der Persistierung gekämpft. Wir bekamen beim abspeichern eine "org.eclipse.persistence.exceptions.QueryException"-Exception, mit der Beschreibung: "Exception Description: The list of fields to insert into the table [DatabaseTable()] is empty. You must define at least one mapping for this table."
Nach einigem Suchen habe ich im Glassfish-Bugtracker einen Hinweis auf diese Exception gefunden. Aller Vermutung nach handelt es sich tatsächlich um einen Bug in eclipselink. In den Kommentaren des Bugtrackers jedoch fand sich auch ein Hinweis, wie man diesen Bug umgehen könnte, obwohl dies vermutlich keine Optimale Lösung darstellt.
In den Entity-Klassen hatten wir zur Definition der IDs die Annotation @GeneratedValue mit der Option "strategy=GenerationType.IDENTITY" benutzt. Diese Stategy-Angabe ruft offensichtlich den Fehler hervor. Nachdem wir diese Option entfernt haben, sprich nur noch die Annotation @GeneratedValue ohne weitere Angaben benutzen, kam der Fehler nicht mehr zum Vorschein.
Nach einigem Suchen habe ich im Glassfish-Bugtracker einen Hinweis auf diese Exception gefunden. Aller Vermutung nach handelt es sich tatsächlich um einen Bug in eclipselink. In den Kommentaren des Bugtrackers jedoch fand sich auch ein Hinweis, wie man diesen Bug umgehen könnte, obwohl dies vermutlich keine Optimale Lösung darstellt.
In den Entity-Klassen hatten wir zur Definition der IDs die Annotation @GeneratedValue mit der Option "strategy=GenerationType.IDENTITY" benutzt. Diese Stategy-Angabe ruft offensichtlich den Fehler hervor. Nachdem wir diese Option entfernt haben, sprich nur noch die Annotation @GeneratedValue ohne weitere Angaben benutzen, kam der Fehler nicht mehr zum Vorschein.
Montag, 21. März 2011
Mapping mit Dozer
Für das Mapping eines Objekts der Logikschicht auf eines der Persistenzschicht benötige ich eine Art Mapper. Zunächst habe ich mir dafür eine Mapperklasse geschrieben, in der ich per Hand ein Objekt eines Typs A in ein Objekt des Typs B umgewandelt habe. Dafür habe ich mir ein sehr einfaches Schema entwickelt und daraus meine Klassen mit JAXB generiert. Für jede Modelklasse musste außerdem eine äquivalente JPA-Klasse erstellt werden. Diese Modelklassen wollte ich nun mit Hilfe der Mapperklasse in eine Klasse mit JPA-Annotationen überführen. Der folgende kurze Codeausschnitt aus der Mapperklasse zeigt das Verfahren:
public class EntityMapper {
public static JpaEntity getJpaEntity(Model model) {
JpaEntity entity = null;
if (model instanceof Adresse) {
entity = new AdresseJpaEntity();
((AdresseJpaEntity) entity).setId(((Adresse) model).getId());
((AdresseJpaEntity) entity).setStrasse(((Adresse) model).getStrasse());
((AdresseJpaEntity) entity).setNummer(((Adresse) model).getNummer());
((AdresseJpaEntity) entity).setOrt(((Adresse) model).getOrt());
((AdresseJpaEntity) entity).setPlz(((Adresse) model).getPlz());
return entity;
}
else if (model instanceof Artikel) {
entity = new ArtikelJpaEntity();
((ArtikelJpaEntity) entity).setId(((Artikel) model).getId());
((ArtikelJpaEntity) entity).setBezeichnung(((Artikel) model).getBezeichnung());
((ArtikelJpaEntity) entity).setHersteller(((Artikel) model).getHersteller());
((ArtikelJpaEntity) entity).setPreis(((Artikel) model).getPreis());
}
...
}
}
Bereits bei diesen wenigen einfachen Modelklassen hat sich gezeigt, dass das Mappen einen enormen zusätzlichen Aufwand bedeutet. In dem Beispiel ist das Mapping nur für zwei Klassen und nur von Model zu JPA-Entity dargestellt.
Nach einigen Gesprächen mit anderen Entwicklern wurde mir "Dozer" (http://dozer.sourceforge.net/documentation/about.html) empfohlen. Dozer nimmt genau diese Arbeit ab. Das Framework ist sehr einfach einzubinden. Bereits die folgenden Zeilen genügen um ein Mapping zubewirken:
AdresseJpaEntity adresseJpaEntity;
Adresse adresse = new Adresse("Musterstraße","1a","02826","Görlitz");Mapper mapper = new DozerBeanMapper();
adresseJpaEntity = mapper.map(adresse, AdresseJpaEntity.class); Dozer erkennt anhand des Names der Klassenattribute welche Attribute aufeinander zu mappen sind. Falls man sich nicht an diese Konvention halten will, man die Mappingregeln in einer XML-Datei spezifizieren.
Abonnieren
Posts (Atom)