V 2.8 TLGen Handbuch EJB3 Code-Generator Version 2.8 (Deutsch) Autoren: Titus Livius Rosu ([email protected]) Titus Rosu ([email protected]) Liviu Rosu ([email protected]) TLGen 1 StarData GmbH V 2.8 Inhaltsverzeichnis 1. Allgemeine Information ____________________________________________________ 9 1.1 Ziele______________________________________________________________________ 11 1.2 TLGen´s Architektur-Konzept __________________________________________________ 12 1.2.1 1.2.2 1.3 Code-Generierung mit Hilfe von TLGen __________________________________________ 14 1.3.1 1.3.2 2 Input für die Code-Generierung _______________________________________________________ 13 Verwendung von Callback-Klassen als Fachlogig Interfaces _________________________________ 14 Code-Generierung mit einem Domain-Modell (UML für neue Projekte) _______________________ 16 Generierung mit einer schon vorhandenen Datenbank (für Legacy Projekte) ___________________ 17 TLGen Code-Generierung und die Datenbankanalyse ____________________________ 19 2.1 Analyse des Domainmodells und der Datenbank __________________________________ 20 2.1.1 Verwendung von UML Parameter (Tags) für die Code-Generierung __________________________ 24 2.1.1.1 UML Parameter für Klassen ______________________________________________________ 24 2.1.1.2 UML Parameter für Attribute ____________________________________________________ 24 2.1.1.3 Was wird generiert ____________________________________________________________ 25 2.1.1.3.1 Relationen _________________________________________________________________ 25 2.1.1.3.1.1 Assoziation ____________________________________________________________ 26 2.1.1.3.1.2 Aggregation ____________________________________________________________ 31 2.1.1.3.1.3 Komposition ___________________________________________________________ 35 2.1.1.3.2 Berechnete Relationen überschreiben __________________________________________ 40 3 Beschreibung der generierten Komponenten (Java Klassen) ______________________ 41 3.1 Daten Klassen - Interfaces ____________________________________________________ 41 3.1.1 3.1.2 3.2 Generierung von „JSon“-Klassen für REST calls ___________________________________________ 42 Generierung von Mapping-Klassen zwischen Daten- und JSon-Klassen ________________________ 43 Session Bean _______________________________________________________________ 46 3.2.1 Interfaces für eine Session Bean ______________________________________________________ 48 3.2.2 XML Persistente Datei ______________________________________________________________ 49 3.2.3 Interface-Klassen zu Fachlogik(Bussiness logic)-Komponenten ______________________________ 50 3.2.4 Interceptors_______________________________________________________________________ 50 3.2.5 Generierung der REST-Schnittstelle ____________________________________________________ 51 3.2.5.1 Client-Seite ___________________________________________________________________ 53 3.3 Clients, BCI (Business Common Interface)________________________________________ 54 3.3.1 Test-Klassen ______________________________________________________________________ 55 3.3.1.1 Attribute für <Test> Tag Annotation _______________________________________________ 56 Test-Klasse Name mit vollem path ______________________________________________ 57 3.3.1.2 3.3.1.3 3.4 3.4.1 3.4.2 TLGen Verwendung von Test-Daten aus externen Dateien __________________________________ 57 “Junit” Test-Klasse für “REST”-calls ________________________________________________ 58 Entity Manager-Klasse _______________________________________________________ 58 Methoden im Entity-Manager ________________________________________________________ 61 Entity Manager-Interfaces ___________________________________________________________ 63 2 StarData GmbH V 2.8 3.5 Entity Beans _______________________________________________________________ 64 3.5.1 Relationen in Entity Beans ___________________________________________________________ 68 3.5.1.1 Relation „OneToMany“ _________________________________________________________ 68 3.5.1.2 Relation „ManyToOne“ _________________________________________________________ 70 3.5.1.3 Relation „OneToOne“ __________________________________________________________ 70 3.5.1.4 Relation „ManyToMany“ ________________________________________________________ 71 3.5.2 Meta-Klassen (für Criteria) ___________________________________________________________ 74 3.6 „Message Driven“ Bean ______________________________________________________ 74 3.7 Services ___________________________________________________________________ 75 3.7.1 3.7.2 3.8 „Timer Service“ ____________________________________________________________________ 75 „Web Services“ ____________________________________________________________________ 77 Callback-Klasse _____________________________________________________________ 78 3.8.1 Free Klassen ______________________________________________________________________ 79 3.9 Generierung von Datenbank und SQL Skripte_____________________________________ 80 3.10 Regel für die Namengenerierung _______________________________________________ 82 3.11 Log Dateien - Beschreibung ___________________________________________________ 83 3.12 Verwendung von Kommentarien bei generiertem Code ____________________________ 84 3.12.1 3.12.2 4 Kommentarien für Klassen _________________________________________________________ 84 Kommentarien für Methoden ______________________________________________________ 85 Verwendung von TLGen (Beschreibung der Konfigurationsdatei) __________________ 86 4.1 Was wird generiert __________________________________________________________ 86 4.2 Wie wird Code generiert? ____________________________________________________ 86 4.3 Ordnerstruktur für den generierten Code ________________________________________ 86 4.4 Default Konfigurationsdatei __________________________________________________ 88 4.4.1 Default Konfigurationsdatei - Struktur __________________________________________________ 88 4.4.2 Default Konfigurationsdatei - Beschreibung _____________________________________________ 90 4.4.2.1 <Standard> Tag _______________________________________________________________ 90 4.4.2.2 <Project> Tag _________________________________________________________________ 90 4.4.2.3 <Locator> Tag _________________________________________________________________ 90 4.4.2.4 <Class> Tag ___________________________________________________________________ 91 4.4.2.5 <Entity> Tag __________________________________________________________________ 91 4.4.2.6 <Mapping> Tag _______________________________________________________________ 92 4.4.2.7 <Criteria> Tag _________________________________________________________________ 92 4.4.2.8 <JSon> Tag ___________________________________________________________________ 92 4.4.2.9 <Manager> Tag _______________________________________________________________ 93 4.4.2.9.1 Fields für Entity Manager _____________________________________________________ 93 4.4.2.9.2 Methoden für Entity Manager _________________________________________________ 93 4.4.2.10 <Session> Tag _________________________________________________________________ 94 4.4.2.10.1 Methoden in Session Bean ___________________________________________________ 95 4.4.2.10.2 <Client> Tag ______________________________________________________________ 95 4.4.2.10.3 <Xml-persistence> Tag ______________________________________________________ 96 4.4.2.10.4 <Interceptor> Tag __________________________________________________________ 96 4.4.2.11 <Message Driven> Tag __________________________________________________________ 96 4.4.2.12 <UmlControl> Tag _____________________________________________________________ 96 TLGen 3 StarData GmbH V 2.8 4.4.2.13 4.4.2.14 4.5 <Method> tag _______________________________________________________________ 100 <Variable> Tag _______________________________________________________________ 100 Projekt Konfigurationsdatei __________________________________________________ 100 4.5.1 Projekt Konfigurationsdatei - Struktur _________________________________________________ 101 4.5.2 Projekt Konfigurationsdatei - Beschreibung ____________________________________________ 102 4.5.2.1 <Generator> Tag _____________________________________________________________ 102 4.5.2.1.1 Regel für Namen-Transformation in Klassen, Methoden und Tabellen ________________ 103 4.5.2.2 <Project> Tag ________________________________________________________________ 104 4.5.2.3 <Locator> Tag ________________________________________________________________ 109 4.5.2.4 <Design> Tag ________________________________________________________________ 109 4.5.2.4.1 Regel für package Generierung _______________________________________________ 109 4.5.2.4.2 <Commentary> Tag ________________________________________________________ 109 4.5.2.4.3 <Class> Tag _______________________________________________________________ 110 4.5.2.4.4 <Entity> Tag ______________________________________________________________ 110 4.5.2.4.5 <Manager> Tag ____________________________________________________________ 111 4.5.2.4.5.1 Feldern (Variable) für Entity Manager ______________________________________ 111 4.5.2.4.5.2 Methoden für Entity Manager ____________________________________________ 111 4.5.2.4.5.2.1 Entity Menager Methoden Typ 6 ______________________________________ 112 4.5.2.4.5.2.2 Entity Menager Methoden Typ 7 ______________________________________ 113 4.5.2.4.5.2.3 Entity Menager Methoden Typ 8 ______________________________________ 114 4.5.2.4.5.2.4 Entity Menager Methoden Typ 9 ______________________________________ 117 4.5.2.4.5.2.5 Entity Menager Methoden Typ 10 _____________________________________ 118 4.5.2.4.5.2.6 Entity Menager Methoden Typ 11 _____________________________________ 118 4.5.2.4.5.3 Manager Interfaces _____________________________________________________ 118 4.5.2.4.6 <Session> Tag _____________________________________________________________ 118 4.5.2.4.6.1 Methoden für Session Bean ______________________________________________ 119 4.5.2.4.6.2 <Client> tag ___________________________________________________________ 119 4.5.2.4.6.3 <Xml-persistence> Tag __________________________________________________ 121 4.5.2.4.6.4 < Timerservice> Tag ____________________________________________________ 121 4.5.2.4.6.5 < Web Service> Tag _____________________________________________________ 122 4.5.2.4.6.6 <Interceptor> Tag ______________________________________________________ 123 4.5.2.4.6.7 <Freeclass> Tag ________________________________________________________ 123 4.5.2.4.6.8 <Callback> Tag ________________________________________________________ 123 4.5.2.4.7 < Message Driven> Tag _____________________________________________________ 124 4.5.2.4.7.1 <Client> Tag für Message Driven Bean _____________________________________ 124 4.5.2.4.7.2 <Bean> Tag für Message Driven Bean ______________________________________ 124 4.5.2.4.7.3 <Callback> Tag für Message-Driven Bean ___________________________________ 125 4.5.2.4.8 <Test> Tag ________________________________________________________________ 126 4.5.2.4.8.1 Generierung von Methoden für Test-Klassen ________________________________ 126 4.5.2.4.9 <Dbtable> Tag _____________________________________________________________ 126 4.5.2.4.9.1 <Relation> Tag, Verwendung von Relationen ________________________________ 126 4.5.2.5 <Method> Tag _______________________________________________________________ 127 4.5.2.6 <Variable> Tag _______________________________________________________________ 128 5 Verwendung von TLGen bei Softwarentwicklung (Bedingungsanleitung) und das Beispiel „Demo“-Beschreibung _______________________________________________________ 130 6 5.1 TLGen-Verwendung in einem neuen IT Projekt, „Demo“ Beispiel ____________________ 130 5.2 Verwendung von TLGen in ein Legacy IT Projekt, „Legacy“ - Beispiel _________________ 135 TLGen Installation _______________________________________________________ 136 TLGen 4 StarData GmbH V 2.8 6.1 Verwendete Tools und Externe Programme _____________________________________ 137 6.2 Verwendung von „ant“ für die Generierung von Java Code _________________________ 138 6.3 Verwendung von „Maven“ für die Generierung von Java Code ______________________ 138 7 Beispiele von generiertem Code ____________________________________________ 140 7.1 Standard Konfigurationsdatei ________________________________________________ 140 7.2 Konfigurationsdatei ________________________________________________________ 144 7.3 SQL Skript ________________________________________________________________ 149 7.4 Klassen und Interfaces ______________________________________________________ 152 7.4.1 7.4.2 7.4.3 7.4.4 7.5 Data-Klassen _____________________________________________________________________ 152 Interface-Data ____________________________________________________________________ 154 JSon Data-Klasse __________________________________________________________________ 155 Mapping zwischen Data-Klassen und JSon Klasse ________________________________________ 156 Session Bean ______________________________________________________________ 158 7.5.1 7.5.2 7.5.3 7.5.4 7.6 Session Bean-Klassen ______________________________________________________________ 158 Session Bean Interface _____________________________________________________________ 166 Client Factory-Klasse _______________________________________________________________ 167 Session Bean REST Interface _________________________________________________________ 168 Entity Manager Bean _______________________________________________________ 168 7.6.1 7.6.2 Entity Manager Bean-Klasse _________________________________________________________ 168 Entity Manager Bean Interface ______________________________________________________ 174 7.7 Entity Bean _______________________________________________________________ 175 7.8 Interceptor-Klasse _________________________________________________________ 178 7.9 Timerservice-Klasse ________________________________________________________ 179 7.10 Web Service ______________________________________________________________ 180 7.11 REST-Klassen ______________________________________________________________ 181 7.11.1 7.11.2 7.12 Client Seite ____________________________________________________________________ 181 Server Seite ____________________________________________________________________ 186 Message Driven Bean _______________________________________________________ 187 8 Vergleich zwischen TLGen und andere Code-Generatoren _______________________ 190 9 Literaturhinweis ________________________________________________________ 192 10 Glossar ______________________________________________________________ 193 Abbildungsverzeichnis Abbildung 1: IT Projekt Architektur________________________________________________________________ 10 Abbildung 2: TLGen Architektur __________________________________________________________________ 13 Abbildung 3: Callback Klassen-Diagramm __________________________________________________________ 14 Abbildung 4: Domain-Modell ____________________________________________________________________ 17 Abbildung 5: Database-Modell ___________________________________________________________________ 18 TLGen 5 StarData GmbH V 2.8 Abbildung 6: TLGen-Generierungsprozess von einem Domain-Modell ____________________________________ 19 Abbildung 7: UML-Klassendiagramm I _____________________________________________________________ 21 Abbildung 8: UML-Klassendiagramm II ____________________________________________________________ 21 Abbildung 9: UML-Klassendiagramm III ____________________________________________________________ 22 Abbildung 10: UML-Klassendiagramm IV ___________________________________________________________ 22 Abbildung 11: UML-Relationen und die TLGen-Gernerierungsparameter _________________________________ 27 Abbildung 12: „OneToMany“-Darstellung im UML-Domainmodell ______________________________________ 69 Abbildung 13: „OneToMany“-Darstelung in der Datenbank ____________________________________________ 69 Abbildung 14: „ManyToMany“-Darstellung im UML-Domainmodell _____________________________________ 72 Abbildung 15: „ManToMany“ Darstellung in der Datenbank ___________________________________________ 72 Abbildung 16: Ordner-Struktur ___________________________________________________________________ 87 Tabellenverzeichnis Tabelle 2: UML verwendete Attribute für die Generierung _____________________________________________ 25 Table 3: Java-Typen ____________________________________________________________________________ 41 Tabelle 4: Session Bean Annotationen _____________________________________________________________ 46 Tabelle 5: Attribute für <Test> Tag-Annotation ______________________________________________________ 57 Tabelle 6: Automatisch generierbare Default-Methoden im Entity Manager ______________________________ 59 Tabelle 7: Annotationen für Entity Manager-Klasse __________________________________________________ 61 Tabelle 8: Annotationen für Entity Beans (EJB3) _____________________________________________________ 65 Tabelle 9: Annotationen für „Message Driven“ Bean _________________________________________________ 75 Tabelle 10: Namen-Regel _______________________________________________________________________ 82 Table 11: Attribute für den Generator Tag _________________________________________________________ 102 Tabelle 12: Attribute für den Projekt-Tag __________________________________________________________ 104 Table 13: Attribute- für den „ant“ <target> „genertor“ _______________________________________________ 138 Listingverzeichnis Listing 1: Remote Connect-Klassen ________________________________________________________________ 19 Listing 2: Import Code __________________________________________________________________________ 20 Listing 3: Code für Variable mit vollem Path ________________________________________________________ 20 Listing 4: “OneToOne” Assoziation ________________________________________________________________ 27 Listing 5: “OneToMany” Assoziation - One__________________________________________________________ 28 Listing 6: “OneToMany” Assoziation - Many ________________________________________________________ 29 Listing 7: „ManyToMany“ Assoziation - Many _______________________________________________________ 29 Listing 8: “ManyToMany” Assoziation - Many 1 _____________________________________________________ 30 Listing 9: “ManyToMany” Assoziation - Many 2 _____________________________________________________ 31 Listing 10: “OneToOne” Aggregation ______________________________________________________________ 32 Listing 11: “OneToMany” Aggregation - One ________________________________________________________ 33 Listing 12: “OneToMany” Aggregation - Many ______________________________________________________ 33 Listing 13: „ManyToMany“ Aggregation - Many _____________________________________________________ 34 Listing 14: “ManyToMany” Aggregation - Many 1 ___________________________________________________ 34 Listing 15: “ManyToMany” Aggregation - Many 2 ___________________________________________________ 35 Listing 16: “OneToOne” Komposition ______________________________________________________________ 37 Listing 17: “OneToMany” Komposition - One________________________________________________________ 37 Listing 18: “OneToMany” Komposition - Many ______________________________________________________ 38 Listing 19: “ManyToOne” Komposition - Many ______________________________________________________ 38 TLGen 6 StarData GmbH V 2.8 Listing 20: “ManyToMany” Komposition - Many 1 ___________________________________________________ 39 Listing 21: “ManyToMany” Komposition - Many 2 ___________________________________________________ 39 Listing 22: Listen ______________________________________________________________________________ 42 Listing 23: Klassen _____________________________________________________________________________ 42 Listing 24: „JSon“ Data-Klasse ___________________________________________________________________ 43 Listing 25: Mapping zwischen einer Data-Klasse und einer„JSon“ Data-Klasse _____________________________ 45 Listing 26: Session Bean ________________________________________________________________________ 48 Listing 27: Session Bean Interface_________________________________________________________________ 49 Listing 28: Persisitence XML _____________________________________________________________________ 49 Listing 29: Interceptor __________________________________________________________________________ 51 Listing 30: REST-Methode in der Konfigurationsdatei _________________________________________________ 52 Listing 31: REST Methode Parameter ______________________________________________________________ 52 Listing 32: REST-Annotations und Parameter in der Konfigurationsdatei __________________________________ 53 Listing 33: REST Beispiel ________________________________________________________________________ 53 Listing 34: REST-calls vom Client __________________________________________________________________ 54 Listing 35: Server Remote Call____________________________________________________________________ 55 Listing 36: Client Class __________________________________________________________________________ 55 Listing 37: Client Interface ______________________________________________________________________ 55 Listing 38: Test-Klasse - Beispiel __________________________________________________________________ 56 Listing 39: Externe Test-Daten ___________________________________________________________________ 57 Listing 40: XML Schema für externe Test-Daten _____________________________________________________ 58 Listing 41: “Find by name” Method _______________________________________________________________ 60 Listing 42: “Find by Primary Key” Method __________________________________________________________ 61 Listing 43: SQL Named Beispiel ___________________________________________________________________ 62 Listing 44: SQL Native Beispiel ___________________________________________________________________ 63 Listing 45: Criteria Beispiel ______________________________________________________________________ 63 Listing 46: Entity Manager Interface Beispiel ________________________________________________________ 64 Listing 47: Entity Bean __________________________________________________________________________ 65 Listing 48: Entity Bean “call…” Helper Methods ______________________________________________________ 67 Listing 49: Entity Bean Sequence Generator ________________________________________________________ 67 Listing 50: Entity Bean (Mapping) ________________________________________________________________ 68 Listing 51: Entity Bean – “OneToMany” Interface ____________________________________________________ 68 Listing 52: ”OneToMany” - Entiy-Bean-Methode _____________________________________________________ 69 Listing 53: „ManyToOne“ Entity-Methode __________________________________________________________ 70 Listing 54: „OneToOne” Data-Interface ____________________________________________________________ 71 Listing 55: „OneToOne” Entity Bean _______________________________________________________________ 71 Listing 56: „ManyToMany“-Interface ______________________________________________________________ 71 Listing 57: „ManyToMany“-Relation in Entity Bean___________________________________________________ 73 Listing 58: Meta-Klasse - Beispiel _________________________________________________________________ 74 Listing 59: Beispiel eines „Timer Services“ __________________________________________________________ 77 Listing 60: „Web Service“-Klasse - Beispiel __________________________________________________________ 77 Listing 61: „Web Service”-Interface _______________________________________________________________ 78 Listing 62: Callback-Klasse - Beispiel_______________________________________________________________ 79 Listing 63: SQL Skript ___________________________________________________________________________ 81 Listing 64: Error Log Datei _______________________________________________________________________ 84 Listing 65: Kommentarien für Klasse ______________________________________________________________ 84 Listing 66: Kommentar vom <Design> Tag __________________________________________________________ 84 Listing 67: Kommentar vom UMD Domain-Modell ___________________________________________________ 85 Listing 68: Methoden Kommentar ________________________________________________________________ 85 Listing 69: Default Konfigurationsdatei ____________________________________________________________ 89 Listing 70: <Column> Tag _______________________________________________________________________ 97 TLGen 7 StarData GmbH V 2.8 Listing 71: Default Values für <ColType> Tag, z.B. für Oracle ___________________________________________ 97 Listing 72: Default Values für <ColType> Tag, z.B. für MySQL ___________________________________________ 98 Listing 73: <NameChange> Tag __________________________________________________________________ 98 Listing 74: Konfigurationsdatei __________________________________________________________________ 102 Listing 75: „Java“ Code style ____________________________________________________________________ 107 Listing 76: „C“ Code style ______________________________________________________________________ 108 Listing 77: SQL Fields __________________________________________________________________________ 111 Listing 78: Methode Type „6“ in der Konfigurationsdatei _____________________________________________ 112 Listing 79: Methode Typ “6” in Entity Manager-Klasse _______________________________________________ 113 Listing 80: Methode Type “7” in der Konfigurationsdatei _____________________________________________ 113 Listing 81: Methode Type “7” Entity Manager-Klasse ________________________________________________ 114 Listing 82: Methode Typ “7” in der Entity-Klasse ____________________________________________________ 114 Listing 83: Methode Typ „8“ in der Konfigurationsdatei ______________________________________________ 114 Listing 84: Methode Typ „8“ in Entiy-Klasse ________________________________________________________ 116 Listing 85: Daten-Klasse für die Methode Typ „8“ ___________________________________________________ 117 Listing 86: Client Interface _____________________________________________________________________ 120 Listing 87: Factory Client Class __________________________________________________________________ 120 Listing 88: Client call‘s _________________________________________________________________________ 121 Listing 89: Konfigurationsdatei-Eintrag für eine Timer Service-Klasse ___________________________________ 122 Listing 90: Message Driven Bean ________________________________________________________________ 125 Listing 91: Callback-Klasse für eine Message Driven Bean ____________________________________________ 126 Listing 92: Verwendung von <tlgen> Tag __________________________________________________________ 136 Listing 93: Maven „pon.xml“ Datei _______________________________________________________________ 139 TLGen 8 StarData GmbH V 2.8 1. Allgemeine Information „Wissen ist Macht“ hat der englische Philosoph Francis Bacon im sechzehnten Jahrhundert gesagt. Um sich Wissen anzueignen, braucht man Daten. Daten sind darstellbare Elemente einer Information, mit deren Hilfe Eigenschaften einer Aktivität beschrieben und in Systemen verarbeitet werden. Heutzutage entsprechen diese Systeme den Computern, die in einer digitalen Form Daten verarbeiten. Durch die stetig ansteigende Computerleistung in Verbindung mit Datenbankensystemen und Vernetzung (z.B. durch das Internet) werden wir von Daten überflutet, die Systeme regelrecht zusammenbrechen lassen. Für den Tagesablauf benötigen wir eine Fülle an Informationen (z.B. Banküberweisungen, eMailverkehr, CRM/ERP-Systeme), die wir immer öfter nicht mehr in einer effizienten Form erhalten (z.B. Systemabstürze, Unterbrechungen, fehlende Daten). Ein Hauptgrund dieser Problematik findet sich in den Verfahren - Datensuche- und -verfahren -. Das heutige Standardverfahren für die Datenverwaltung der Informationen bevorzugt den Einsatz von relationalen Datenbanken (z. B. Oracle, DB2 von IBM, MySQL, SQL Server von Microsoft etc.) sowie von Applikation Servern (z. B. JBoss, WebLogic von Oracle, WebSphere von IBM etc.). Die zwei Komponenten - Datenbanken und Application Server - werden in eine Persistenzschicht integriert, welche Teil eines Programms ist, das die Fachlogik darstellt, notwendig für eine bestimmte Aktivität (siehe Abbildung 1). Der Nutzer (User) verwendet ein Programm über die Bedieneroberfläche (GUI oder Web), die sich meist auf einem getrennten Computer, dem Client, befindet. Der Client holt sich die Informationen, die er benötigt, von einem Server, wo sich die Fachlogik des Programms sowie die Datenbank befinden. Nach heutigem technischen Stand wird die Steuerung der Kommunikation zwischen Client und Server durch einen Application Server gesteuert, der gleichzeitig die Daten innerhalb der Datenbank mit Hilfe von so genannten CRUDs (Create, Read, Update, Delete) verwaltet. Die Persistenzschicht ist ein essentiell wichtiger Teil eines jeden IT Programms und verursacht den Hauptanteil der Programmentwicklungskosten zusammen mit Wartung und Erweiterungen durch neue Features. Der Kostenaufwand wird durch den Einsatz von relationalen Datenbanken weiter ausgebaut. - Erhöhte Kosten im IT Sektor werden verursacht von: Falscher Modellierung von Daten-Modellen sowie der Anwendung von nicht genormten Daten-Modellen (wichtig ist die dritte Normalform) Historisch gewachsenen Daten-Modellen Nicht optimaler Gestaltung der Persistenzschicht, die den Aufwand von Wartung und Weiterentwicklung erhöht Mischung von technischem mit fachlichem Code (siehe Anmerkung) Anmerkung: In der Softwareentwicklung unterscheidet man drei Typen von Code: Technischer Code: Code, der zu 100 % unabhängig von der Fachlogik und daher komplett generierbar ist. Generierbarer Code: Ist gemischter Code, der aus technischem und fachlogischem Code besteht (nur Datenstruktur). Dieser Code Typ lässt sich zu 40% bis 80 % generieren und somit reduziert dieser die Entwicklungs-, Wartungs- sowie Weiterentwicklungs-Kosten von IT Projekten: TLGen 9 StarData GmbH V 2.8 o In Fehler! Verweisquelle konnte nicht gefunden werden. entspricht dieser Code Typ den Session Beans, der Persistence Data (Objects/Interfaces), den Entity Managern, der Entities Beans, BCI, JUnit (Test) und den Interfaces der Business Tier-, d.h. 40-80 % der Entwicklungskosten eines IT Projekt. Fachlogik-Code: Ist zu 100 % spezifisch für jedes einzelne IT Projekt. Zu diesem Typ gehören z.B. die Gestaltung der Oberfläche (Präsentation Tier) oder die Kommunikationsschnittstellen für Partnersysteme etc. Abbildung 1: IT Projekt Architektur TLGen ist ein Code-Generator für den gemischten Java Code auf Basis von EJB 3, eine Thematik, die detailliert in Kapitel 1 erläutert wird (siehe auch www.tlgen.com). TLGen 10 StarData GmbH V 2.8 In Kapitel 2 wird die Verwendung von TLGen mit der genauen Offenlegung seiner Features in Kombination mit der Ordnerstruktur der Konfigurationsdatei, woraus man die Projektarchitektur gestalten kann, beschrieben. Dieses Kapitel behandelt TLGen Möglichkeiten wie z.B. die Optimierung von Datenmodellen oder Vermeiden von Kreisen in Datenmodelle. Dieses Kapitel gibt auch Anweisungen für eine optimale TLGen-Verwendungen IT Projekten. Kapitel 3 beschreibt die generierten Java Klassen anhand von Beispielen, d.h. eine detaillierte Beschreibung der generierten Java Klassen. Kapitel 4 beschreibt die Konfigurationsdateien und gleichzeitig die Logdateien, die bei der Generierung entstehen. Kapitel 5 beschreibt zwei komplette Beispiele für die TLGen Verwendung Kapitel 6 Beschreibung der TLGen-Installation Kapitel 7 gibt einige Beispiele für den generierten Code Kapitel 8 Sonstige Code-Generatoren im Vergleich mit TLGen 1.1 Ziele TLGen ist ein Code-Generator auf Basis von EJB3 mit Java Annotationen. Ziel unserer Arbeit war, die Kosten für die Backend-Softwareentwicklung durch eine komplette Generierung von Code zu minimieren. Aktuelle Code-Generatoren auf Basis des MDA Ansatzes (AndroMDA, Rapsody etc.) benötigen nach der Generierung auch einen bedeutenden Arbeitsaufwand durch die Entwickler, nachträgliches Customizing, so dass der angesetzte Zeitgewinn durch weiteren Aufwand verfällt. Der Mix aus generiertem Code und dem von Programmierern entwickelten Code (manuelle Entwicklung) führen in der Realität zu einer Anzahl von Problemen (unterschiedliche Logik, Layout, Auseinanderdriften von Modell und Code, Fehler etc.). Dies ist der Grund, warum der Ansatz von TLGen eine klare Trennung zwischen den generierten und den manuell entwickelten Code fordert. In der IT wurde des Öfteren bewiesen, dass sich ein sehr großer Teil von Code vollständig generieren lässt. TLGen ermöglicht diese Generierung mit Hilfe des Daten-Inputs in Form eines Domainmodells (neue Projekte) oder einer schon existieren Datenbank (Refactoring Projekte von Legacy Systemen) in Verbindung mit zwei Konfigurationsdateien (beinhalten die Steuerungsparameter für die Generierung). TLGen benötigt zwei Konfigurationsdateien: eine für allgemeine Definitionen wie Daten-Typen, Konvertierung, etc., die nur selten zu ändern ist (wird mit TLGen mitgeliefert) und eine ProjektKonfigurationsdatei, die wichtige Informationen beinhaltet wie Namen, Regeln, Umwandlungen, Projekt-Struktur (wichtig für Legacy-Projekte), Verknüpfung von Tabellen zu bestimmten Session Beans usw. Zusätzlich bietet TLGen die Möglichkeit zu einer Datenbank- oder eine Domainmodell-Analyse und unterbreitet Vorschläge für deren Optimierung. Ist die Entwicklungsphase eines IT-Projektes beendet, werden stetig weitere Features für neue Praxis-Anforderungen implementiert und somit die benötigte Datenbank durch Erweiterung angepasst (gemeint ist nur die Datenstruktur). Diese historisch wachsenden Datenbanken führen eher selten zu einer Fortführung optimaler Datenstrukturen und letztendlich zu hohen Wartungskosten in Verbindung mit dem Zwangsstart von Refactoring Projekten. TLGen 11 StarData GmbH V 2.8 Das Datenmodell sollte, mindestens in der dritten Normalform vorliegen (siehe z.B. http://de.wikipedia.org/wiki/Normalisierung_%28Datenbank%29 ). Die Normalisierung ist ein wichtiges Hilfsmittel, um die Konsistenz der Daten zu gewährleisten. Das erleichtert die Wartung sowie die Upgrade-Möglichkeiten für zukünftige Anforderungen der Applikation, ohne die Datensätze zu verändern. Da es für viele Datenbanken keine grafische Darstellung der Datenstruktur gibt, um so die Möglichkeit der Optimierung des Datenmodells zu gewährleisten, wird die Arbeit der Erstellung eines neuen Modells erheblich erschwert. TLGen bietet jetzt die Möglichkeit an, aus einem existierenden Datenbankmodell die Grafik bzw. das Domainmodell zu generieren, zusammen mit Optimierungsvorschlägen. Durch die schnelle Code-Generierung können diese Änderungen sofort für die obligatorischen Projekt-Tests bereitstehen und somit einen schnellen Überblick über das Entwicklungsvorhaben ermöglichen. Diese grafische Darstellung als Domainmodell (UML) ist für die Optimierung einer alten Datenbank sehr wichtig. Des Weiteren wird erst durch das neu-erstellte Domainmodell eine Generierung des Backend’s möglich, da jede Zeile aus einer Datenbanktabelle als Java Bean-Objekt im generierten Code abgebildet wird (dabei spielt es keine Rollte, ob als Join/Mapping aus mehreren Tabellen oder aus einer Zeile einer Tabelle). Der generierte Backend-Code entspricht dem Software-Architekturkonzept, welches in Abbildung 2 anschaulich erklärt wird. 1.2 TLGen´s Architektur-Konzept In Abbildung 2 wird das Architektur-Konzept von TLGen zusammen mit den Komponenten, welche TLGen generiert, dargestellt: Test-Klassen(JUnit), Data-Klassen/Interfaces JSon-Klassen Mapping-Klassen zwischen Data und JSon-Klassen Sessions Beans Entity Manager Entity Beans Message Driven Beans Timer Services Web Services REST Interface Klassen Callback-Klassen (siehe Abbildung 3) Free Klassen Log-Dateien (beschreiben im Detail die generierten Elemente) TLGen 12 StarData GmbH V 2.8 Datenbank-Skripte (notwendig, um eine Datenbank zu erstellen) Für das Ändern einer schon vorhandenen Datenbank werden nur die Differenz Skripte generiert, um so die existierenden Daten nicht zu löschen. Für die Änderung einer existierenden Datenbank werden nur die Differenz Skripte generiert, um so die vorhandenen Daten nicht zu löschen. Diese Skripte können direkt in dem Generierungsprozess verwendet werden oder erst bei Bedarf (siehe Kapitel 4). Abbildung 2: TLGen Architektur 1.2.1 Input für die Code-Generierung Damit TLGen den Code generieren kann, wird folgender Input benötigt: Ein Datenstruktur-Modell, welches entweder ein Domainmodell (siehe Fehler! Verweisquelle konnte nicht gefunden werden.) sein kann, designed in UML für den Start neuer IT-Projekte (siehe Kapitel 2) oder ein Datenbankmodell (z. B. eine existierende Datenbank – Abbildung 5) beim Einsatz in Legacy-Projekten (siehe Kapitel 2), die einen Refactoring Prozess benötigen. Eine Default Konfigurationsdatei (im XML-Format), welche die Werte für Definitionen beinhaltet wie z.B. allgemeine Regeln für die Namen-Konventionen, UML Domainmodell Regel, Standard-Methoden für die Datenbankzugriffe, eine Tabelle mit Konvertierung zwischen den Variablen-Typen in Java Code und in der Datenbank. Eine Konfigurationsdatei (im XML-Format) mit unterschiedlichen Informationen, abhängig vom Projekt (siehe Kapitel 4). Oben genannte Input-Informationen werden in Projekten immer von den Designern oder Datenmodellieren erstellt. Lediglich die Konfigurationsdatei ist neu für den Code, denn das Datenoder Datenbankmodell (DM oder DB) ist in der Entwicklung von IT-Projekten immer eine Notwendigkeit. TLGen 13 StarData GmbH V 2.8 1.2.2 Verwendung von Callback-Klassen als Fachlogig Interfaces Callback-Klassen werden verwendet, um eine komplette Trennung zwischen den von TLGen generierten Code und den vom Programmierer entwickelten Code zu erzielen. So wird die Merge (Mischung) technisch komplett ausgeschlossen. Nach unserer Erfahrung hat die Mischung von generiertem Code mit dem vom Programmierer entwickelten Code in vielen Projekten zahlreiche Schwierigkeiten ergeben. Die Architektur-Darstellung für die Verwendung von Callback-Klassen ist in Abbildung 3 und eine detaillierte Beschreibung dieser Technologie findet sich in Kapitel 3.8. Abbildung 3: Callback Klassen-Diagramm Diese Klassen können zusammen mit den generierten SessionBean-Klassen (Message Driven Bean, Entity Manager, REST, Web-Service, Timer-Service) verwendet werden. 1.3 Code-Generierung mit Hilfe von TLGen Im fortlaufenden Kapitel werden alle detaillierten Möglichkeiten beschrieben, die TLGen für die Codegenerierung sowie der Datenbankenanalyse bietet. Die detaillierte Struktur der Konfigurationsdateien wird in Kapitel 4.4 erläutert. Wie schon in Kapitel 1.2 erwähnt, steuert TLGen den Generierungsprozess mit Hilfe von zwei Konfigurationsdateien, eine für Default-Werte, die in der Regel keinen großen Änderungsbedarf erweist sowie eine Konfigurationsdatei, die individuell für jedes Projekt ist. TLGen bietet für die Code-Generierung folgende Möglichkeiten an: TLGen Das Einbauen von Kommentare innerhalb des generierten Codes (siehe Kap. 3.12) 14 StarData GmbH V 2.8 Regel für die Namen-Generierung der Datenbanken sowie für den generierten Code (siehe Kap. 3.10) Der Einsatz aller Annotationen im generierten Code, die EJB3 anbietet Informationen für die Generierung mit Hilfe von Apache Tool „ant“; TLGen hat eigene „ant“ Tag, <tlgen> beschrieben in Kapitel 6 Der generierte Code entspricht dem EJB 3-Standard und ist auf allen Applicationen Server, die zur Zeit am Markt vertreten sind (WebLogic, WebSphere, JBoss, GlasFish, IoNas, etc.), verwendbar. Folgender Code wird generiert: o Daten-Klassen, Daten-Interfaces, Daten JSon-Klassen und die MappingKlassen zwischen Daten-Klassen und JSon-Klassen (siehe Kap. 3.1) o Session Beans, Interfaces für Session Beans, XML „persistence“ Datei, REST Dateien, Interceptors Dateien mit allen Annotationen (siehe Kap. 3.2) o Entity Manager-Klassen für die Steuerung von Entitie Beans mit allen möglichen Zugriffen (Methoden) für CRUD (Create, Read, Update, Delete). Beim Manager ist es auch möglich, eigene SQLs (werden aus den Konfigurationsdateien gelesen) für Criteria Methoden (siehe Kap. 3.4) einzubinden bzw. aufzurufen. o Entities Beans, wo alle Relationen automatisch generiert werden (vom Domain-Modell oder aus der Datenbank) - OneToOne, OneToMany, ManyToOne, ManyToMany (siehe Kap. 3.5) o Meta Klassen für die Verwendung bei Criteria Call’s (siehe Kap. 3.5.2) o Clients Klassen für BCI (Business Common Interfaces); Diese ermöglichen die Verbindung zwischen Client und Server (Session Beans) (siehe Kap. 3.2). o Test-Klassen auf Basis von JUnit. Die Daten für Test-Klassen können durch TLGen generiert oder von einer XML Datei geladen werden. Auch die Struktur der XML-Daten-Dateien kann von TLGen generiert werden. Test-Klassen sind in zwei Modi zu verwenden, indem die Daten direkt geprintet oder über die Mechanismen von JUnit getestet werden. Die JUnit Test Klassen können für „remote“ call’s und REST call’s generiert werden (siehe Kap. 3.3.1) o REST Schnittstelle (siehe Kap. 3.2.5) o Datenbank-Skripte (in SQL Sprache, um die Datenbank anzulegen oder zu verwalten (siehe Kap. 7.3) o Callback-Klassen als Interfaces für Fachlogik-Code (siehe Kap. 3.8) o Interceptoren o XML Datei für Persistenz (persistence.xml), eine für jede Session Bean o Message Driven-Bean Klassen o Service-Klassen: Timer Service (siehe Kap. 3.7.1) Web Service (siehe Kap. 3.8.1) TLGen kann mit dem „ant“ Apachen Tool genutzt werden, da TLGen einen eigenen Tag „generator“ besitzt. TLGen 15 StarData GmbH V 2.8 1.3.1 Code-Generierung mit einem Domain-Modell (UML für neue Projekte) Die Generierung mit Hilfe eines Domain-Modells als Informations-Input findet seine Anwendung bei neuen IT-Projekten. Ein IT-Architekt (oder ein Architektur-Team, projektabhängig) gestaltet zusammen mit der Fachabteilung ein Domain-Modell, das die Datenstruktur und dessen Verbindungen für das Programm darstellt. Auf diese Basis kann man letztendlich mit TLGen den kompletten Code generieren und diesen sofort testen. Für solche Projekte bietet TLGen zu den Eigenschaften aus Kapitel 2.1 noch zusätzliche Möglichkeiten an, wie: Eine Analyse des Domain-Modells mit Suche nach falschen Namen (z. B. zu lang für eine Datenbank), eventuelle Kreise in den Verbindungen zwischen Objekten (Tabellen) und mögliche Verbesserungsvorschläge (siehe Kap. 2.1). Innerhalb von einem Domain-Modell können Klassen-Typen und Enume verwendet werden. Daten- und Klassen-Typen können in jeder beliebigen Art und Weise verschachtelt werden, so wie die benötigte Logik der Applikation. TLGen 16 StarData GmbH V 2.8 Abbildung 4: Domain-Modell 1.3.2 Generierung mit einer schon vorhandenen Datenbank (für Legacy Projekte) Nachdem TLGen einen Zugang zur Datenbank erhalten hat, übernimmt TLGen alle relevanten Informationen für die Code-Genierung wie z.B. Tabellen, Spalten, Relationen, Sequenzen etc. TLGen ist kompatibel zu allen aktuellen Datenbanken. Für ein Projekt, dass mit einer Datenbank als Input startet (z.B. Refactoring von LegacySystemen) bietet TLGen zu den in Kap. Fehler! Verweisquelle konnte nicht gefunden werden. aufgelisteten Eigenschaften weitere Möglichkeiten an, wie: Optimale Verwendung von Tabellen, Spalten etc. für den generierten Code gemäß den existierenden Namen-Konventionen im Code Generierung von Datenbank Skripte für eine neue Änderungsskripte, die dann nur die Differenzen beinhalten TLGen 17 Datenbank oder nur StarData GmbH V 2.8 Abbildung 5: Database-Modell TLGen 18 StarData GmbH V 2.8 2 TLGen Code-Generierung und die Datenbankanalyse TLGen ist ein einfaches Tool mit einem technischen Hintergrund auf höchstes Niveau für die Generierung von Backend Code auf Basis von EJB3. Wie in den Kapiteln zuvor erklärt, generiert TLGen den Code von einem Domain- (siehe Abbildung 4) oder Datenbankmodell (siehe Abbildung 5) und bietet gleichzeitig Optimierungsmöglichkeiten der Modelle nach eigener Analyse an. Abbildung 6: TLGen-Generierungsprozess von einem Domain-Modell In diesem Kapitel werden detailliert die generierten Objekte sowie zur Verfügung stehende Steuerungsmöglichkeiten beschrieben. Allgemeine Features, die zentral für die gesamte Generierung möglich sind (für Details siehe Kap. 4): Projekt-Name Application Server, z.B. „JBoss“, “Weblogic” etc. Der Application Server ist für die Verwendung des generierten Codes für „Clients“ wichtig, weil jeder Application Server eigene Darstellung für die Variable „datasource“ und für die Verbindung zwischen Client und Server in „remote modus“ eigene Klassen verwendet . initialcontextfactory="org.jnp.interfaces.NamingContextFactory" initialcontextpkgprefix="org.jboss.naming:org.jnp.interfaces" Listing 1: Remote Connect-Klassen Datenbank-Namen mit Zugriff für die berechtigten User samt Passwörter zum Auslesen der Informationen (Tabellen, Spalten, Sequences, etc. für Legacy Projekte oder Ziele, wo die Tabellen generiert werden sollten) Projekt-Steuerungs-Attribut. Ein Refactoring-Projekt wird durch eine schon vorhandene Datenbank (wichtig bei vorhandener Legacy-IT) oder Entwicklung einer neuen Applikation durch ein Domainmodell gesteuert. Bei Generierung einer neuen Datenbank kann diese vollständig neu erstellt oder nur die Änderungen übernommen werden, ohne schon vorhandene Daten zu löschen. TLGen 19 StarData GmbH V 2.8 Notwendige Informationen für die Generierung von SQL Skripte wie Tablespace etc. „ear“ Datei-Name Die generierte Code-Formatierung kann frei gewählt werden (Standard JavaFormatierung z.B. mit geschweiften Klammern in derselben oder nächsten Zeile oder z.B. die Anzeige der Import-Deklarationen am Klassenanfang oder direkt im Code mit den vollständigen Import). import eu.stardata.core.hlp.dataif.CoLanguageDataIf; import javax.persistence.OneToMany; class { private CoLanguageDataIf … … } Listing 2: Import Code oder ohne Import in Code: Class { @ javax.persistence.OneToMany(cascade = { javax.persistence.CascadeType.PERSIST}, targetEntity = eu.stardata.server.core.formular.entity.PageEntity.class) private eu.stardata.server.core.doclist.entity.DocumentlistEntity … … } Listing 3: Code für Variable mit vollem Path 2.1 Analyse des Domainmodells und der Datenbank Die Relationen vonKlassen eines Domainmodells oder von Datenbank-Tabellen können je nach Anforderungen unterschiedlich komplex sein. Betrachten wir als Beispiel Abbildung 7 eines UML-Klassendiagramms, wo beim Neuanlegen der Klasse C mindestens ein B über zwei verschiedene Pfade gleichzeitig benötigt werden. Existiert jedoch kein B, muss dieses erst neuangelegt werden. Dies ist in diesem Fall aber nur möglich, falls ein C über eine Relation von Pfad A schon existiert. Das Klassendiagramm ist logisch nicht inkorrekt (z.B. ist A ein Produkt, B ein Element des Produkts und C ein Bestellauftrag). Aber die Klassen des Beispiels Domainmodell, jeweils als Tabelle in einer Datenbank abgebildet, führen zum Problem, dass C ein B benötigt (not null) wie A (not null), doch gleichzeitig benötigt A auch ein B (not null), dass zu diesem Zeitpunkt schon vorhanden sein müsste. TLGen 20 StarData GmbH V 2.8 Abbildung 7: UML-Klassendiagramm I Anmerkung: Ein UML-Klassendiagramm, wo beim Neuanlegen der Classe C B über 2 verschiedene Pfade benötigt wird. Beim Neuanlegen von B kann dieses dagegen noch nicht existieren, da C noch nicht über die Relation von Pfad A existiert. Kreise, durch Pfade in der Erreichbarkeit der Klasse „C“, sind hier wie folgt: Die Klasse „C“ ist über die Klasse „B“ durch folgende Pfade erreichbar: [B (NOT NULL)->A (NOT NULL)] ---> [C] [B (NOT NULL)] ---> [C] Genau in diesem Schema werden alle Pfade in der Erreichbarkeit einer Klasse (hier „C“), über welche Klassen (hier „B“) diese Pfade verlaufen, in der Debug-Log Datei bei der Generierung des Codes durch TLGen dargestellt. Fälle wie in Fehler! Verweisquelle konnte nicht gefunden werden. werden mit einem „Fatal Error“ in der Debug-LOG Datei und Error-LOG Datei ausgegeben. Dagegen werden Kreise von Relationspfaden, die nicht über unterschiedliche Klassen in der Zielklasse enden, mit einem „Warning“ angezeigt (vgl. Abbildung 8). Abbildung 8: UML-Klassendiagramm II Anmerkung: Wie Abbildung 7, aber in der Relation von [B(Null)] ---> [C] ist null erlaubt. Somit kann B und C über den Relationen von A gleichzeitig angelegt werden. Direkte Kreise, d.h. Zielklasse ist auch die Startklasse in einem Relationspfad, werden in den LOG-Dateien als „Fatal Error“ deklariert (vgl. Abbildung 9), falls alle Klassen im TLGen 21 StarData GmbH V 2.8 Relationspfad voneinander abhängig sind (hier: [A (NOT NULL)->C (NOT NULL) ->B (NOT NULL)] ---> [A]) und nur mit einem „Warning“, falls dies nicht zutrifft (vgl. Abbildung 7: [A (NOT NULL)->C (NULL) ->B (NOT NULL)] ---> [A]) Abbildung 9: UML-Klassendiagramm III Anmerkung: Ein direkter Relationspad, wo jede Startklasse auch Zielklasse ist und alle voneinander abhängig sind. Abbildung 10: UML-Klassendiagramm IV Anmerkung: Ein direkter Relationspad, wo jede Startklasse auch Zielklasse ist, aber nicht alle voneinander abhängig sind. Im Folgenden ist ein Knoten mit einer Klasse des Domainmodells oder einer Datenbanktabelle äquivalent. Die Debug-LOG Datei beinhaltet folgende Informationen, um Pfade zu analysieren: „CHECK RELATIONS METHODS - Adjacency list”: Die Liste zeigt alle Knoten (TARGET) an, die über verschiedene Relationspfade erreicht werden können: Node: 'TARGET': TLGen 22 StarData GmbH V 2.8 [ungeordneter Relationspfad] ---> [TARGET] [alle passierte Vorknoten der Pfade aufsummiert] Beispiel: [C,B] ---> [A] [C(1),B(2)] „CHECK RELATIONS METHODS - CIRCLE PATH (direct)”: Die Liste zeigt alle Kreise der Knoten (TARGET) an, die über verschiedene Relationspfade über den TARGET selber erreicht werden können: Node: 'TARGET': [geordneter Relationspfad beginnend mit TARGET] ---> [TARGET] Beispiel: [A(NULL)->C (NOT NULL)->B (NOT NULL)] ---> [A] „CHECK RELATIONS METHODS - ALL PATHS”: Die Liste zeigt alle Pfade der Knoten (TARGET) an, die über andere Knoten erreicht werden können: Node: 'TARGET': [geordneter Relationspfad] ---> [TARGET] Beispiel: [C (NOT NULL)->B (NOT NULL)] ---> [A] Wenn neben dem Pfad ein „FATAL” angeziegt wird, dann ist TARGET von sich selbst abhängig. „CHECK RELATIONS METHODS - CIRCLE PATHS (not direct)”: Die Liste zeigt alle Pfade der Knoten (TARGET) an, die von verschiedenen Knoten (SOURCE) über unterschiedliche Relationspfade erreicht werden können: 'TARGET': 'SOURCE': [geordneter Relationspfad mit SOURCE] ---> [TARGET] Beispiel: -'C': [C (NOT NULL)->B (NOT NULL)] ---> [A] Wenn neben dem Knoten SOURCE „FATAL” angeziegt wird, dann sind mehrere Pfade, die in TARGET enden, von SOURCE abhängig (siehe oben, z.B. [C->D]--->[A] und [C>B]--->[A]). Wird ein „Warning” angezeigt, dann sind mehrere Pfade, die in TARGET enden, von SOURCE abhängig, wobei diese über denselben Knoten in TARGET (siehe oben, z.B. [C->D->B]--->[A] und [C->B]--->[A]) enden. Die Error-LOG Datei beinhaltet folgende Informationen, um Pfade zu analysieren: „Direct circles in relations” o „Warning“, wenn es einen Relationspfad gibt, wo Start- und Endknoten gleich sind. Beispiel: [A (NULL)->B (NOT NULL)] ---> [A]) TLGen 23 StarData GmbH V 2.8 o „FATAL Error“, wenn es einen Relationspfad gibt, wo Start- und Endknoten gleich und voneinander abhängig sind. Beispiel: [A (NOT NULL)->B (NOT NULL)] ---> [A] „Relation Problems?” o „Warning“, wenn man den Zielknoten über verschiedene Relationspfade desselben Startknotens erreichen kann und diese voneinander abhängig sind, aber der Zielknoten immer über denselben Vorgängerknoten endet. Beispiel: [C (NOT NULL)->B (NOT NULL)] ---> [A] und [C (NOT NULL)->D (NOT NULL)->B (NOT NULL)] ---> [A]) o „FATAL Error“, wenn man den Zielknoten über verschiedene Relationspfade desselben Startknotens erreichen kann und diese voneinander abhängig sind. Beispiel: [C (NOT NULL)->B (NOT NULL)] ---> [A] und [C (NOT NULL)->D (NOT NULL)] ---> [A] 2.1.1 Verwendung von UML Parameter (Tags) für die Code-Generierung 2.1.1.1 UML Parameter für Klassen Folgende UML Parameter werden für die Klassengenerierung (siehe Fehler! Verweisquelle konnte nicht gefunden werden.) in verschieden UML Tools verwendet: Tabelle 1: UML Verwendete Parameter für die Generierung Nr. 1 2 Enterprise Architekt Name Package 3 Parsistence 4 Notes 5 Constrains 6 Links 7 LinksMultiplicity 8 Links-Type 9 LinksDirection Magic Draw RMI Tags/Attribut Description UML:Class.name tag="package_name" value=”Package-Name” tag="persistence" value="Persistent/Transient" Class Name This value is used to build the class path (view 4.5.2.4) For „Persistent“ a Table and a class data is generate in the database, for “Transient” only a class data is generated Class Description tag="documentation" value=".. Description ..” UML:Constraint name="SQL constraint” UML:Association tag="ea_type" value="Aggregation" tag="direction" value="Destination ->t; Source" Constrains for database SQL script. View 5.b.iii Defined the links between two classes with all parameters (Source Role, Target Role) Define the Multiplicity from link. OneToOne, OneToMany, ManyToOne or ManyToMany Define the Links Type (keine, Aggregation, Composition) or Define Direction (Unspezified, BiDerectional, Source->Destination, Destination->Source) 2.1.1.2 UML Parameter für Attribute TLGen 24 StarData GmbH V 2.8 Folgende UML Parameter werden für die Variablen-Generierung (siehe Tabelle 1) für verschiedene UML Design Tools verwendet: Tabelle 1: UML verwendete Attribute für die Generierung Nr. Enterprise Architekt Magic Draw 1 Name Get the variable name 2 Type Variable Type, i.e. String, int, long, other class, an predefiniert enum, etc 3 Attribute is a Collection/Container Type Atrributlänge (in DB) 4 Initial Initial value 5 Notes Attribute description 6 Derived Is used to define the database, if this field is null or not null 7 Constrint/Type Process 8 Static = Description Call a method for chifer/entchifer by write and read in the DB Define, if this field is unique in the database 2.1.1.3 Was wird generiert Damit die Code-Generierung aus einem UML-Diagramm (für TLGen der XML-Export von Enterprise Architekt in UML 1.3 / UML2.0) die gewünschten Ergebnisse liefert, muss man die UML-Relationen und Parameter entsprechend für TLGen konfigurieren. Standardmäßig sind bestimmte Attribute für TLGen fest gewählt und können in der Default Konfigurationsdatei entsprechend angepasst werden. Im Folgenden werden die Standard-Parameter von TLGen erklärt und die Ergebnisse in Code-Beispielen aufgezeigt. 2.1.1.3.1 Relationen Mit den Relationen lassen sich die Abhängigkeiten der UML-Klassen in einem DomainModell logisch aufzeigen. Damit TLGen EJB-Code und die Entity-Beans Abhängigkeiten untereinander generiert, sind die UML-Relationen zu den verschieden EJB OneToOne-, OneToMany-, ManyToOne- und ManyToMany-Relationen (siehe Kapitel 3.5.1) standardmäßig konfiguriert und werden im Folgenden erläutert (mit Code-Beispiel). Natürlich können diese Einstellungen für eigene projektspezifische Anforderungen in der Default Konfigurationsdatei verändert werden. TLGen 25 StarData GmbH V 2.8 Mit Hilfe der drei verschiedenen UML Assoziationen „Assoziation“, „Aggregation“ und „Komposition“, die Relations-Richtung (B->A „Source to Destination“ oder B<-A „Destination to Source“), Navigation und Multiplizität (z.B. 0-*, 0-1 oder 1) wird die Relationsart OneToOne-, OneToMany-, ManyToOne- und ManyToMany generiert. Diese berechneten Generierungen der Relationsarten können nochmals von der Relationsart selber in der Konfigurationsdatei überschrieben werden (siehe Kapitel 2.1.1.3.2). Anmerkung: Im UML Programm Enterprise Architect kann man die Navigation explizit ändern, d.h. B->A „Source to Destination“ oder B<-A „Destination to Source“ zu B<-A „Source to Destination“ oder B->A „Destination to Source“, aber die Richtungsart bleibt erhalten. Dies erkennt TLGen, um weitere EJB-Relationsarten in der Generierung zu ermöglichen (z.B. siehe Paramenter in Kapitel 2.1.1.3.1.2). Der EJB Tag „@JoinColumn“-Parameter „insertable“, „updatable“, „nullable“, „optional“ und der Relationsart-Tag-Parameter (von z.B. „@OneToMany“) „cascade“ werden anhand der Multiplizität (z.B. nullable=true|false) und der Relationsart festgelegt (siehe Abbildung 8: UML-Klassendiagramm II). 2.1.1.3.1.1 Assoziation Die Verwendung der einfachen Assoziation generiert alle Relationsarten OneToOne-, OneToMany-, ManyToOne- und ManyToMany anhand der Multiplizität (z.B. „1-*“). Die Richtung spielt hier keine Rolle (siehe Abbildung 11). Parameter: - cascade: Cascade wird nicht generiert. - insertable: Ist immer true. - updateable: Ist immer true. - nullable: Abhängig von der Multiplizität. TLGen 26 StarData GmbH V 2.8 Abbildung 11: UML-Relationen und die TLGen-Gernerierungsparameter Anmerkung: Alle Parameter sind über die Konfigurationsdatei steuerbar. Die genau eingestellten Parameter sind in den Kapiteln der Relationen „Assoziation“, „Aggregation“ und „Komposition“ erklärt. OneToOne Beispiel: Die Source-Klasse Offer (Source) hat eine Assoziation mit der Klasse AccessControl (Target) mit der Richtung Source->Destination und Multiplizität 1->0..1 Folgender Relations-Code wird nur in die Entity-Klasse Offer generiert: private AccessControlEntity m_accessControl = null; ... @OneToOne(targetEntity = AccessControlEntity.class,optional = true) @JoinColumn(name = "AccessControl_ID",insertable = true, updatable = true, nullable = true, unique = false, referencedColumnName = "AccessControl_ID") public AccessControlEntity getAccessControl () { return m_accessControl; } public void setAccessControl (AccessControlEntity arg) { m_accessControl = arg; } Listing 4: “OneToOne” Assoziation TLGen 27 StarData GmbH V 2.8 OneToMany Beispiel: Die Source-Klasse ServiceDescription (Source) hat eine Assoziation mit der Klasse AccessControl (Target) mit der Richtung Source->Destination (Navigation auf Destination) und Multiplizität 1->0..* (->AccessControl). Dies entspricht einer OneToManyRelation von ServiceDescription zu AccessControl. Anmerkung: Die Verwendung der mappedby-Funktion für OneToMany wird in der Konfigurationsdatei aktiviert (siehe Kapitel 4.5.2.2 <Project> Tag). OneToMany-Relation vom Entity ServiceDescription zum Entity AccessControl: Klasse ServiceDescription: private List<AccessControlEntity> m_accessControl = new ArrayList<AccessControlEntity>(); ... @OneToMany(targetEntity = AccessControlEntity.class) @JoinColumn(name = "ServiceDescription_ID") public List<AccessControlEntity> getAccessControl() { return m_accessControl; } public void setAccessControl(List<AccessControlEntity> arg) { m_accessControl = arg; } MappedBy: private AccessControlEntity m_accessControl = null; ... @OneToMany(mappedBy = "serviceDescription",targetEntity = AccessControlEntity.class) public List<AccessControlEntity> getAccessControl () { return m_accessControl; } public void setAccessControl (List<AccessControlEntity> arg) { m_accessControl = arg; } Listing 5: “OneToMany” Assoziation - One Die Entity-Klassen AccessControl der Relation werden in einer Array-Liste gespeichert. Das gilt für die dazugehörige Daten-Klasse. Klasse AccessControl: private ServiceDescriptionEntity m_serviceDescription = null; ... @ManyToOne(optional = true,targetEntity = ServiceDescriptionEntity.class) @JoinColumn(name = "ServiceDescription_ID",insertable = true, updatable = true, nullable = false, unique = false,referencedColumnName = "ServiceDescription_ID") public ServiceDescriptionEntity getServiceDescription() { return m_serviceDescription; TLGen 28 StarData GmbH V 2.8 } public void setServiceDescription(ServiceDescriptionEntity arg) { m_serviceDescription = arg; } MappedBy: private ServiceDescriptionEntity m_serviceDescription = null; ... @ManyToOne(optional = true,targetEntity = ServiceDescriptionEntity.class) @JoinColumn(name = "ServiceDescription_ID",insertable = true, updatable = true, nullable = false, unique = false,referencedColumnName = "ServiceDescription_ID") public ServiceDescriptionEntity getServiceDescription() { return m_serviceDescription; } public void setServiceDescription(ServiceDescriptionEntity arg) { m_serviceDescription = arg; } Listing 6: “OneToMany” Assoziation - Many ManyToOne Beispiel: Die Source Klasse Access (Source) hat eine Assoziation mit der Klasse Order (Target) mit der Richtung Source->Destination und Multiplizität 0..*->0..1 Folgender Relations-Code wird nur in die Entity-Klasse Access generiert (keine OneToManyRückverbindung im Order- Entity): Klasse Access: private OrderEntity m_order = null; ... @ManyToOne(optional = true,targetEntity = OrderEntity.class) @JoinColumn(name = "OrderTable_ID",insertable = true, updatable = true, nullable = true, unique = false,referencedColumnName = "OrderTable_ID") public OrderEntity getOrder() { return m_order; } public void setOrder(OrderEntity arg) { m_order = arg; } Listing 7: „ManyToMany“ Assoziation - Many ManyToMany Beispiel: Die Source Klasse Service (Source) hat eine Assoziation mit der Klasse Location (Target) mit der Richtung Source->Destination und Multiplizität 0..*->0..* Anmerkung: Die Verwendung der mappedby-Funktion für ManyToMany wird in der Konfigurationsdatei aktiviert (siehe Kapitel 4.5.2.2 <Project> Tag). ManyToMany-Relation vom Entity Service zum Entity Location: TLGen 29 StarData GmbH V 2.8 Klasse Service: private List<LocationEntity> m_location = new ArrayList<LocationEntity>(); ... @ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE}, mappedBy = "service",targetEntity = LocationEntity.class) public List<LocationEntity> getLocation() { return m_location; } public void setLocation(List<LocationEntity> arg) { m_location = arg; } MappedBy: private List<LocationEntity> m_location = new ArrayList<LocationEntity>(); ... @ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE},mappedBy = "serviceDescription",targetEntity = LocationEntity.class) public List<LocationEntity> getLocation() { return m_location; } public void setLocation(List<LocationEntity> arg) { m_location = arg; } Listing 8: “ManyToMany” Assoziation - Many 1 ManyToMany -Relation vom Entity Location zum Entity Service: Klasse Location: private List<ServiceEntity> m_service = new ArrayList<ServiceEntity>(); ... @ManyToMany(targetEntity = ServiceDescriptionEntity.class) @JoinTable(name = "Service_Location",inverseJoinColumns = {@JoinColumn(name = "Service_ID",insertable = true, updatable = true, nullable = true, unique = false)},joinColumns = {@JoinColumn(name = "Location_ID",insertable = true, updatable = true, nullable = true, unique = false)}) public List<ServiceEntity> getService() { return m_service; } public void setService(List<ServiceEntity> arg) { m_service = arg; } MappedBy: private List<ServiceEntity> m_service = new ArrayList<ServiceEntity>(); ... @ManyToMany(targetEntity = ServiceEntity.class) TLGen 30 StarData GmbH V 2.8 @JoinTable(name = "Service_Location",inverseJoinColumns = {@JoinColumn(name = "Service_ID",insertable = true, updatable = true, nullable = true, unique = false)},joinColumns = {@JoinColumn(name = "Location_ID",insertable = true, updatable = true, nullable = true, unique = false)}) public List<ServiceEntity> getService() { return m_service; } public void setService(List<ServiceEntity> arg) { m_service = arg; } Listing 9: “ManyToMany” Assoziation - Many 2 In beiden Entity-Klassen werden die anderen Entities der Relation in Array-Listen gespeichert, genauso in den Daten-Klassen. Die Mapping Tabelle Service_Location wird automatisch mit generiert (siehe Kapitel 3.5.1.4 Relation „ManyToMany“) 2.1.1.3.1.2 Aggregation Die Verwendung der Aggregation als stärkere Klassenbindung generiert auch alle Relationsarten OneToOne-, OneToMany-, ManyToOne- und ManyToMany durch die Multiplizität (z.B. „1-*“) und anhand der Richtung, ob ein OneToMany (Destination-> Source) oder ein ManyToOne (Source->Destination) generiert wird. Parameter Relation “< >=====” mit "Source -> Destination” und Navigation ="Source": - nullable: Abhängig von der Multiplizität. Parameter Relation “< >====>” mit "Source -> Destination” und Navigation ="Target": - nullable: Abhängig von der Multiplizität. - insertable="true" - updateable="true" - cascade="PERSIST,MERGE" Parameter Relation “< >=====” mit " Destination -> Source” und Navigation =" Target": - nullable: Abhängig von der Multiplizität. Parameter Relation “< >====>” mit " Destination -> Source” und Navigation =" Source ": - nullable: Abhängig von der Multiplizität. - insertable="true" - updateable="true" - cascade="PERSIST " TLGen 31 StarData GmbH V 2.8 Konfigurationseinstellung in der XML: /** -- Relation: < >=====" | Direction: "Source -> Destination" | Navigation: <= to Source" --------------------- **/ <Association type="Shared" name="Shared:Source -> Destination|toSource" position="Source" navigable="Source" nullable ="true"n comment="Relation: &#60; >===== | Direction: 'Source -> Destination' | Navigation: '&#60;= to Source'"/>n" /** -- Relation: < >====>" | Direction: "Source -> Destination" | Navigation: "=> to Destination" ----------- **/ <Association type="Shared" name="Shared:Source -> Destination|toTarget" position="Source" navigable="Target" nullable ="true" insertable="true" updateable="true" cascade="PERSIST,MERGE" comment="Relation: &#60; >====> | Direction: 'Source -> Destination' | Navigation: '=> to Destination'"/> /** -- Relation: < >=====" | Direction: "Destination -> Source" | Navigation: <= to Destination" ----------------- **/ <Association type="Shared" name="Shared:Destination -> Source|toTarget" position="Target" navigable="Target" nullable ="true"n comment="Relation: &#60; >===== | Direction: 'Destination -> Source' | Navigation: '&#60;= to Destination'"/> /** -- Relation: < >====>" | Direction: "Destination -> Source" | Navigation: "=> to Source" ----- **/ <Association type="Shared" name="Shared:Destination -> Source|toSource" position="Target" navigable="Source" nullable ="true" insertable="true" updateable="true" cascade="PERSIST" comment="Relation: &#60; >====> | Direction: 'Destination -> Source' | Navigation: '=> to Source'"/> OneToOne Beispiel: Die Source Klasse Corporate (Target) hat eine Aggregation mit der Entity-Classe Config (Source) mit der Richtung Destination->Source (Navigation auf Source) und Multiplizität 0..1->0..1 (->Config). Dies entspricht einer OneToOne-Relation von Corporate zu Config. OneToOne-Relation vom Entity Rückverbindung im Entity Config): Corporate zum Entity Config (keine OneToOne Klasse Corporate: private ConfigEntity m_config = null; ... @OneToOne(cascade = {CascadeType.PERSIST},targetEntity = ConfigEntity.class,optional = true) @JoinColumn(name = "Config_ID",insertable = true, updatable = true, nullable = true, unique = false,referencedColumnName = "Config_ID") public ConfigEntity getConfig() { return m_config; } public void setConfig(ConfigEntity arg) { m_config = arg; } Listing 10: “OneToOne” Aggregation TLGen 32 StarData GmbH V 2.8 OneToMany Beispiel: Die Source Klasse Customer (Target) hat eine Aggregation mit der Klasse CustomerHistory (Source) mit der Richtung Destination->Source (Navigation auf Source) und Multiplizität 0..1->0..* (->CustomerHistory). Dies entspricht einer OneToManyRelation von Customer zu CustomerHistory. Anmerkung: Die Verwendung der mappedby-Funktion für OneToMany wird in der Konfigurationsdatei aktiviert (siehe Kapitel 4.5.2.2 <Project> Tag). OneToMany-Relation vom Entity Customer zum Entity CustomerHistory: Klasse Customer: private List<CustomerHistoryEntity> m_customerHistory = new ArrayList<CustomerHistoryEntity>(); ... @OneToMany(cascade = {CascadeType.PERSIST}, mappedBy = "customer",targetEntity = CustomerHistoryEntity.class) public List<CustomerHistoryEntity> getCustomerHistory() { return m_customerHistory; } public void setCustomerHistory (List<CustomerHistoryEntity> arg) { m_customerHistory = arg; } Listing 11: “OneToMany” Aggregation - One Die Entity-Klassen CustomerHistory der Relation werden in einer Array-Liste gespeichert, genauso in der Daten-Klasse von Customer. Klasse CustomerHistory: private CustomerEntity m_customer = null; ... @ManyToOne(optional = true,targetEntity = CustomerEntity.class) @JoinColumn(name = "Customer_ID",insertable = true, updatable = true, nullable = true, unique = false,referencedColumnName = "Customer_ID") public CustomerEntity getCustomer() { return m_customer; } public void setCustomer(CustomerEntity arg) { m_customer = arg; } Listing 12: “OneToMany” Aggregation - Many TLGen 33 StarData GmbH V 2.8 ManyToOne Beispiel: Die Source Klasse Cos (Target) hat eine Aggregation mit der Klasse Corporate (Source) mit der Richtung Destination->Source (Navigation auf Source) und Multiplizität 1->0..* (->Cos). Dies entspricht einer ManyToOne-Relation von Cos zu Corporate. ManyToOne-Relation von Cos zum Entity Corporate (keine OneToMany Rückverbindung zu Corporate): Klasse Corporate: private CosEntity m_cos = null ... @ManyToOne(optional = true,targetEntity = CosEntity.class) @JoinColumn(name = "Cos_ID",insertable = true, updatable = true, nullable = false, unique = false,referencedColumnName = "Cos_ID") public CosEntity getCos() { return m_cos; } public void setcos(CosEntity arg) { m_cos = arg; } Listing 13: „ManyToMany“ Aggregation - Many ManyToMany Beispiel: Die Source Klasse Sub (Target) hat eine Aggregation mit der Klasse App (Source) mit der Richtung Destination->Source (Navigation auf Source) und Multiplizität 0..*->0..* (->App). Dies entspricht einer ManyToMany-Relation von Sub zu App. Anmerkung: Die Verwendung der mappedby-Funktion für ManyToMany wird in der Konfigurationsdatei aktiviert (siehe Kapitel 4.5.2.2 <Project> Tag). ManyToMany -Relation vom Entity Sub zum Entity App: Klasse Sub: private List<AppEntity> m_app = new ArrayList<AppEntity>(); ... @ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE},mappedBy = "sub",targetEntity = AppEntity.class) public List<AppEntity> getApp() { return m_app; } public void setApp(List<AppEntity> arg) { m_app = arg; } Listing 14: “ManyToMany” Aggregation - Many 1 TLGen 34 StarData GmbH V 2.8 ManyToMany -Relation vom Entity App zum Entity Sub: Klasse App: private List<SubEntity> m_sub = new ArrayList<SubEntity>(); ... @ManyToMany(targetEntity = SubEntity.class) @JoinTable(name = "Sub_App",inverseJoinColumns = {@JoinColumn(name = "Sub_ID",insertable = true, updatable = true, nullable = true, unique = false)},joinColumns = {@JoinColumn(name = "App_ID",insertable = true, updatable = true, nullable = true, unique = false)}) public List<SubEntity> getSub() { return m_sub; } public void setSub(List<SubEntity> arg) { m_sub = arg; } Listing 15: “ManyToMany” Aggregation - Many 2 In beiden Entity-Klassen werden die anderen Entities der Relation in Array-Listen gespeichert, genauso in den Daten-Klassen. Die Mapping Tabelle Sub_App wird automatisch mit generiert (siehe Kapitel 3.5.1.4) 2.1.1.3.1.3 Komposition Die Komposition ist die stärkste Verbindungsart (somit „nullable“ nicht immer „true“) und generiert auch alle Relationsarten OneToOne-, OneToMany-, ManyToOne- und ManyToMany, durch die Multiplizität (z.B. „1-*“) und anhand der Richtung, ob ein OneToMany (Destination-> Source) oder ein ManyToOne (Source->Destination) generiert wird. Parameter Relation “<#>=====” mit "Source -> Destination” und Navigation ="Source": - nullable=“false“ - optional="false Parameter Relation “<#>====>” mit "Source -> Destination” und Navigation ="Target": - optional="false" - nullable="true" - insertable="true" - updateable="true" - cascade="PERSIST,MERGE,REMOVE" Parameter Relation “<#>=====” mit " Destination -> Source” und Navigation =" Target": TLGen 35 StarData GmbH V 2.8 - nullable=“false“ - optional="false Parameter Relation “<#>====>” mit " Destination -> Source” und Navigation=" Source ": - optional="false" - nullable="true" - insertable="true" - updateable="true" - cascade="PERSIST,MERGE,REMOVE" Konfigurationseinstellung in der XML: /** -- Relation: <#>=====" | Direction: "Source -> Destination" | Navigation: <= to Source" ----------------------- **/ <Association type="Composition" name="Composition:Source -> Destination|toSource" position="Source" navigable="Source" optional="false" nullable ="false" comment="Relation: &#60;#>===== | Direction: 'Source -> Destination' | Navigation: '&#60;= to Source'"/> /** -- Relation: <#>====>" | Direction: "Source -> Destination" | Navigation: "=> to Destination" ---------------- **/ <Association type="Composition" name="Composition:Source -> Destination|toTarget" position="Source" navigable="Target" optional="false" nullable ="true" insertable="true" updateable="true" cascade="PERSIST,MERGE,REMOVE" comment="Relation: &#60;#>====> | Direction: 'Source -> Destination' | Navigation: '=> to Destination'"/>n" /** -- Relation: <#>====="" | Direction: "Destination -> Source" | Navigation: <= to Destination" --------------- **/ <Association type="Composition" name="Composition:Destination -> Source|toTarget" position="Target" navigable="Target" optional="false" nullable ="false"n comment="Relation: &#60;#>===== | Direction: 'Destination -> Source' | Navigation: '&#60;= to Destination'"/> /** -- Relation: <#>====>" | Direction: "Destination -> Source" | Navigation: "=> to Source" ------------------ **/ <Association type="Composition" name="Composition:Destination -> Source|toSource" position="Target" navigable="Source" optional="false" nullable ="true" insertable="true" updateable="true" cascade="PERSIST,MERGE,REMOVE" comment="Relation: &#60;#>====> | Direction: 'Destination -> Source' | Navigation: '=> to Source'"/> OneToOne Beispiel: Die Source Klasse Product (Source) hat eine Komposition mit der Klasse Asset (Target) mit der Richtung Destination->Source (Navigation auf Product) und Multiplizität 1->1 (->Product). OneToOne-Relation vom Entity Asset zum Entity Product (keine OneToOne Rückverbindung zu Product): TLGen 36 StarData GmbH V 2.8 Klasse Asset: private ProductEntity m_product = null; ... @OneToOne(cascade = {CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE},targetEntity = ProductEntity.class,optional = true) @JoinColumn(name = "Product_ID",insertable = true, updatable = true, nullable = false, unique = false,referencedColumnName = "Product_ID") public ProductEntity getProduct() { return m_product; } public void setProduct(ProductEntity arg) { m_product = arg; } Listing 16: “OneToOne” Komposition OneToMany Beispiel: Die Source Klasse Login (Source) hat eine Komposition mit der Klasse Customer (Target) mit der Richtung Destination->Source (Navigation auf Source) und Multiplizität 0..*->0...1 (->Customer). Anmerkung: Die Verwendung der mappedby-Funktion für OneToMany wird in der Konfigurationsdatei aktiviert (siehe Kapitel 4.5.2.2 <Project> Tag). OneToMany -Relation vom Entity Customer zum Entity Login: Klasse Customer: private List<LoginEntity> m_login = new ArrayList<LoginEntity>(); ... @OneToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE},mappedBy = "customer",targetEntity = LoginEntity.class) public List<LoginEntity> getLogin() { return m_login; } public void setLogin(List<LoginEntity> arg) { m_login = arg; } Listing 17: “OneToMany” Komposition - One Die Entity-Klassen Login der Relation werden in einer Array-Liste gespeichert, genauso in der Daten-Klasse von Customer. TLGen 37 StarData GmbH V 2.8 Klasse Login: private CustomerEntity m_customer = null; ... @ManyToOne(optional = true,targetEntity = CustomerEntity.class) @JoinColumn(name = "Customer_ID",insertable = true, updatable = true, nullable = true, unique = false,referencedColumnName = "Customer_ID") public CustomerEntity getCustomer() { return m_customer; } public void setCustomer(CustomerEntity arg) { m_customer = arg; } Listing 18: “OneToMany” Komposition - Many ManyToOne Beispiel: Die Source Klasse UserRole (Source) hat eine Komposition mit der Klasse AccessControl (Target) mit der Richtung Source->Destination (Navigation auf AccessControl) und Multiplizität 1..*->1 (->AccessControl). ManyToOne-Relation vom Entity AccessControl zum Entity UserRole (keine OneToMany Rückverbindung zu UserRole): Klasse UserRole: private AccessControlEntity m_accessControl = null; ... @ManyToOne(optional = true,targetEntity = AccessControlEntity.class) @JoinColumn(name = "AccessControl_ID",insertable = true, updatable = true, nullable = false, unique = false,referencedColumnName = "AccessControl_ID") public AccessControlEntity getAccessControl() { return m_accessControl; } public void setAccessControl (AccessControlEntity arg) { m_accessControl = arg; } Listing 19: “ManyToOne” Komposition - Many In diesem Beispiel gibt es keine cascade, nur eine starke Bindung (siehe Kapitel 2.1.1.3.2). ManyToMany Beispiel: Die Source Klasse Contract (Target) hat eine Komposition mit der Klasse ServiceDescription (Source) mit der Richtung Destination->Source (Navigation auf TLGen 38 StarData GmbH V 2.8 Source) und Multiplizität 1..*->1..* (->ServiceDescription). ManyToMany-Relation von Contract zu ServiceDescription. Dies entspricht einer Anmerkung: Die Verwendung der mappedby-Funktion für ManyToMany wird in der Konfigurationsdatei aktiviert (siehe Kapitel 4.5.2.2 <Project> Tag). ManyToMany -Relation vom Entity Contract zum Entity ServiceDescription: Klasse Contract: private List<ServiceDescriptionEntity> m_serviceDescription = new ArrayList<ServiceDescriptionEntity>(); ... @ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE},mappedBy = "contract",targetEntity = ServiceDescriptionEntity.class) public List<ServiceDescriptionEntity> getServiceDescription() { return m_serviceDescription; } public void setServiceDescription(List<ServiceDescriptionEntity> arg) { m_serviceDescription = arg; } Listing 20: “ManyToMany” Komposition - Many 1 ManyToMany -Relation vom Entity ServiceDescription zum Entity Contract: Klasse ServiceDescription: private List<ContractEntity> m_contract = new ArrayList<ContractEntity>(); ... @ManyToMany(targetEntity = ContractEntity.class) @JoinTable(name = "Contract_ServiceDescription",inverseJoinColumns = {@JoinColumn(name = "Contract_ID",insertable = true, updatable = true, nullable = false, unique = false)},joinColumns = {@JoinColumn(name = "ServiceDescription_ID",insertable = true, updatable = true, nullable = false, unique = false)}) public List<ContractEntity> getContract() { return m_contract; } public void setContract(List<ContractEntity> arg) { m_contract = arg; } Listing 21: “ManyToMany” Komposition - Many 2 In beiden Entity-Klassen werden die anderen Entities der Relation in Array-Listen gespeichert, genauso in den Daten-Klassen. Die Mapping Tabelle Contract_ServiceDescription wird automatisch mit generiert (siehe Kapitel 3.5.1.4 Relation „ManyToMany“) TLGen 39 StarData GmbH V 2.8 2.1.1.3.2 Berechnete Relationen überschreiben Die OneToOne-, OneToMany-, ManyToOne- und ManyToMany-Relationen, welche wie in Kapitel 2.1.1.3.1 beschrieben, generiert wurden, kann man nochmals über die Einstellungen der Default Konfigurationsdatei überschreiben. Parameter: - overwrite: true, falls vorher Berechnetes überschrieben werden soll . - direction: true, die Richtungseinstellung soll verwendet werden. - optional: @JoinColumn-Parameter - insertable: @JoinColumn-Parameter - updateable: @JoinColumn-Parameter - cascade: z.B. @OneToMany-Parameter Standardmäßig sind folgende Überschreibungen für die Relationen in der Konfigurationsdatei aktiv: - OneToOne: <Association type="OneToOne" name="OneToOne" overwrite="true" direction="true" optional="true" insertable="true" updateable="true"/> - OneToMany: <Association type="OneToMany" name="OneToMany" overwrite="true" direction="true" insertable="true" updateable="true"/> - ManyToOne: <Association type="ManyToOne" name="ManyToOne" overwrite="true" direction="true" optional="true" insertable="true" updateable="true" cascade="null"/> - ManyToMany: <Association type="ManyToMany" name="ManyToMany" overwrite="true" direction="true" optional="true" insertable="true" updateable="true" cascade="PERSIST,MERGE,REMOVE"/> TLGen 40 StarData GmbH V 2.8 3 Beschreibung der generierten Komponenten (Java Klassen) 3.1 Daten Klassen - Interfaces TLGen kann Daten, Klassen/Interfaces aus einem Domainmodell oder aus einer vorhandenen Datenbank generieren. Es wandelt die Datenbank-Tabellen mit seinen Spalten in Klassen/Interfaces mit ihren Variablen um. Es wandelt Daten-Typen von Spalten in Java Daten-Typen um wie in Table 2 dargestellt. Für Sonderwünsche der Typ-Verwendung kann in der Default-Konfigurationsdatei eine eigene Umwandlung definiert werden (siehe Kap. 4.4). Table 2: Java-Typen Nr. Datenbank Type Java (Code) Type 1 CHAR char 2 NCHAR char 3 DATE java.util.Date 4 TIMESTAMP java.util.Date 5 DECIMAL double 6 BINARY_DOUBLE double 7 BINARY_FLOAT float 8 INTEGER int 9 NUMBER long 10 VARCHAR java.lang.String 11 VARCHAR2 java.lang.String 12 NVARCHAR2 java.lang.String 13 LONG java.lang.Long 14 RAW java.lang.String 15 LONG RAW byte[] 16 CLOB java.lang.String 17 NCLOB java.lang.String 18 BLOB byte[] 19 TEXT java.lang.String 20 LONGTEXT java.lang.String 21 INT int 22 BIGINT long 23 DATETIME java.util.Date 24 SMALLINT short TLGen 41 StarData GmbH V 2.8 In Konfigurationsdateien ist es möglich auch die Klassen/Interface Path mit „extends“ zu definieren. Diese „extends“ sind Basis-Klassen/Interfaces, die eventuelle Variablen beinhalten, die die komplette Applikation beinhaltet und können vom TLGen Anwender geschrieben werden. TLGen liefert auch diesen Code für Standard-Anwendungen mit. Diese Superklassen sind für das Programm nicht unbedingt notwendig. TLGen hat auch eigene Basis-Klassen/Interfaces, die als Default verwendet werden, falls der TLGen Anwender nicht eigene schreibt. In Konfigurationsdateien werden auch das Path für Klassen „Typen“ und „Enums“ definiert, falls diese in der Applikation verwendet werden. TLGen generiert für die Relationen, die in der Datenbank oder in dem Domainmodell vorhanden sind, entsprechende Variablen als Liste oder einfache Variablen wie für Interfaces: public abstract List<CoPageDataIf> getPage(); public abstract void setPage(List<CoPageDataIf> arg); Listing 22: Listen private List<CoPageDataIf> m_page; ... public List<CoPageDataIf> getPage() { return m_page; } public void setPage(List<CoPageDataIf> arg) { m_page = arg; } Listing 23: Klassen Für die Klassen/Interfaces, die seitens Domainmodells generiert sind, werden alle Attribute übernommen, persistente und nicht persistente, wobei in den SQL Skripten (die für die Datenbank-Generierung notwendig sind) nur die persistenten Variablen verwendet werden. Für die Klassen/Interfaces, die von einer vorhandenen Datenbank generiert werden, können neue Variablen eingefügt werden, die nicht persistent sind. 3.1.1 Generierung von „JSon“-Klassen für REST calls JSon, JavaScript Object Notation ist ein Datenformat, der für die Datenobjektdarstellung verwendet wird, notwendig für den Datenaustausch zwischen verschiedene Anwendungen. TLGen generiert Daten-Klassen im JSon Format für die REST Schnittstellen. Wenn in der Configdatei beim Tag <Project> ein Attribut „jsonData“ auf „true“ (als Defaultwert ist für dieses Attribut „false“ gesetzt) gesetzt wird, dann wird für jede Daten-Klasse auch ein JSon-Objekt generiert wie in Listing 24. Diese Klassen werden bei der gleichen Addresse wie die Daten-Klassen generiert. TLGen 42 StarData GmbH V 2.8 @XmlRootElement(name = "login") public class LoginJSon implements Serializable { private static final long serialVersionUID = 310747291; // Methods from columns private String name; private long loginID; private String password; private AuthTypeEnum authMethod; private Date modifyDate; // Methods from relations tables private UnitJSon unit; // Methods from columns public String getName() { return name; } public void setName(String arg) { name = arg; } public long getLoginID() { return loginID; } … // Methods from relations tables public UnitJSon getUnit() { return unit; } public void setUnit(UnitJSon arg) { unit = arg; } } Listing 24: „JSon“ Data-Klasse Durch das Attribut „pathJsonData“ kann aber eine andere Adresse für die Generierung von „JSon“-Klassen verwendet werden, z.B. „pathJsonData=“de.firma.project.jsondata““. 3.1.2 Generierung von Mapping-Klassen zwischen Daten- und JSon-Klassen Verwendet man das Attribut „mapping=“true““ in der Config Datei, Tag <Project> generiert TLGen eine Mapping-Datei zwischen jeder Daten-Klasse und eine JSon-Datenklasse in beide Richtungen wie in Listing 25. TLGen 43 StarData GmbH V 2.8 /** * This class map the class data to JSon class data and inverse */ public class UserMap implements Serializable { private static final long serialVersionUID = 268222648; // Mapping methods between class data and JSon data objects /** * Map "UserData" object to "UserJSon" object data * @param json * @return */ public static UserData mapJSonToData(UserJSon json) { UserData data = new UserData(); data.setName(json.getName()); data.setEmail(json.getEmail()); data.setFirstName(json.getFirstName()); data.setUserID(json.getUserID()); data.setTelefon(json.getTelefon()); data.setLastName(json.getLastName()); data.setModifyDate(json.getModifyDate()); data.setLogin(getLoginJSon(json.getLogin())); data.setUserRole(getUserRoleJSonList(json.getUserRole())); return data; } /** * Map "UserJSon" object to "UserData" object data * @param data * @return */ public static UserJSon mapDataToJSon(UserData data) { UserJSon json = new UserJSon(); json.setName(data.getName()); json.setEmail(data.getEmail()); json.setFirstName(data.getFirstName()); json.setUserID(data.getUserID()); json.setTelefon(data.getTelefon()); json.setLastName(data.getLastName()); json.setModifyDate(data.getModifyDate()); json.setLogin(getLoginData(data.getLogin())); json.setUserRole(getUserRoleDataList(data.getUserRole())); return json; } /** * Helper method for mapping * @param data * @return */ private static LoginData getLoginJSon(LoginJSon data) { LoginData objLogin = null; if(data != null) { objLogin = LoginMap.mapJSonToData(data); TLGen 44 StarData GmbH V 2.8 } return objLogin; } /** * Helper method for mapping * @param list * @return */ private static List<UserRoleData> getUserRoleJSonList(List<UserRoleJSon> list) { List<UserRoleData> listUserRole = null; if(list != null && !list.isEmpty()) { listUserRole = new ArrayList<UserRoleData>(); for(UserRoleJSon json : list) { if(json != null) { UserRoleData data = UserRoleMap.mapJSonToData(json); listUserRole.add(data); } } } return listUserRole; } /** * Helper method for mapping * @param data * @return */ private static LoginJSon getLoginData(LoginData data) { LoginJSon objLogin = null; if(data != null) { objLogin = LoginMap.mapDataToJSon(data); } return objLogin; } /** * Helper method for mapping * @param list * @return */ private static List<UserRoleJSon> getUserRoleDataList(List<UserRoleData> list) { List<UserRoleJSon> listUserRole = null; if(list != null && !list.isEmpty()) { listUserRole = new ArrayList<UserRoleJSon>(); for(UserRoleData data : list) { if(data != null) { UserRoleJSon json = UserRoleMap.mapDataToJSon(data); listUserRole.add(json); } } } return listUserRole; } } Listing 25: Mapping zwischen einer Data-Klasse und einer„JSon“ Data-Klasse TLGen 45 StarData GmbH V 2.8 Das Attribut „mapping“ ist als „true“ gesetzt, aber wird nur wenn auch das Attribut „jsonData“ gesetzt ist, verwendet. Falls nur die Generierung von JSon-Klassen jedoch nicht die MappingKlassen gebraucht werden, sollte man das - Attribut „mapping=“false““ verwenden. 3.2 Session Bean Session Bean ist eine wichtige Klasse und die erste Klasse, welche von einem Client über RMI aufgerufen wird. Sie hat innerhalb von EJB3 eine vordefinierte Form und kann mit mehreren Annotationen verwendet werden (siehe Tabelle 3: Session Bean Annotationen). Mit Hilfe der Steuerung über die Konfigurationsdateien können für die Session Beans folgende Features generiert werden: Annotationen mit Parameter Selbst geschriebene „extends“-Klassen oder die von TLGen Default Session Bean Basis-Klassen Interceptoren (siehe 3.2.4) Clients (siehe 3.3) Entity Manager-Klassen (siehe 3.4) Entities Beans (siehe 3.5) XML Persistente Datei (siehe 3.2.2) Definiert die Methoden, die vom Client aufgerufen werden. Diese Methoden können von den Manager-Klassen übernommen werden. Kann bestimmen, welcher Transaktionentyp verwendet wird. Interface-Klassen, welche die Verbindung zwischen generiertem Code und Fachcode ermöglichen. Tabelle 3: Session Bean Annotationen Annotationen Verwendung in TLGen 2.7 Kommentar javax.ejb.Stateless ja Definiert eine Stateless Session Bean javax.ejb.Stateful ja Definiert eine Stateful Session Bean javax.ejb.EJB ja Definiert eine lokale References z. B. Name einer Manger-Interface (siehe 2.5) javax.ejb.Remote ja Bezeichnet eine Remote Verwendung von Session Bean javax.ejb.Local ja Für eine Lokale Verwendung javax.ejb.ApplicationException nein javax.ejb.EJBs ja javax.ejb.Init nein TLGen Definiert eine oder mehreren EJB Annotationen 46 StarData GmbH V 2.8 javax.ejb.LocalHome nein Entspricht nicht der Philosophie von EJB3 javax.ejb.PostActivate ja Methode wird nach dem Aktivierung von Session Bean aufgerufen javax.ejb.PrePassivate ja Nur für Stateful Session Bean javax.ejb.RemoteHome nein Entspricht nicht der Philosophie von EJB3 javax.ejb.Remove ja Call Methode mit den Annotation PreDestroy (nur für Stateful Session Bean) javax.ejb.Timeout ja Session Bean wird nach Ablauf von timeout verworfen javax.ejb.TransactionAttribute ja Transaction Type (REQUIRED, MANDATORY, etc.) javax.ejb.TransactionManagement ja Transaction management (CONTAINER or BEAN) javax.jws.Web Service ja Definiert eine Service die über www aufgerufen werden kann Für eine Session Bean kann man eine oder mehrere Manager-Klassen mit deren Anweisungen für eine optimale TLGen-Verwendung in IT Projekten aufrufen. Von einem Domainmodell kann für jedes Package eine Session Bean generiert werden und innerhalb der Session Bean für jedes Element-Objekt ein Tandem vom Manager, Entity Bean sowie eine Datenbank-Tabelle. Für die Legacy-Projekte (Refactoring), die auf Basis einer vorhandenen Datenbank durchgeführt werden, soll in der Konfigurationsdatei eine Tabellenliste, zugehörig zu einer Session Bean, vorhanden sein. Session Bean Code Beispiel: package eu.stardata.server.core.formular; import eu.stardata.server.core.formular.bci.ExecBci; import eu.stardata.server.core.formular.bci.TablecolBci; … import javax.ejb.EJB; @Stateless(name = FormularBci.JNDI_NAME, mappedName = "efp/"+FormularBci.JNDI_NAME+"/remote") @Remote(FormularBci.class) public class FormularSessionBean extends BaseSessionBean implements FormularBci { private static final long serialVersionUID = 196502766; // Session annotations and fields for local manager @EJB private EntryBci m_EntryBci; … /** * Session method "createEntry()" * @param arg * @return * @throws PersistenceException */ public CoEntryDataIf createEntry(CoEntryDataIf arg) throws PersistenceException { try { TLGen 47 StarData GmbH V 2.8 return m_EntryBci.create(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex,1); } } } Listing 26: Session Bean 3.2.1 Interfaces für eine Session Bean Session Bean benötigt eine Interface mit allen definierten Methoden, die vom Client aufgerufen werden. Diese Interfaces für Session Bean verwenden zwei Annotationen: @Remote für eine Remote-Verbindung vom Client sowie @Local für eine lokale Verwendung. In diesem Interface sind auch drei vordefinierte Variablen, die für EJB3 sehr wichtig sind: String JNDI_NAME = Wert, ist der notwendige Name für den Client-Aufruf und eindeutig für die gesamte Applikation. TLGen verwendet für diese Variable den Inhalt des kompletten Session Bean Namens, z. B. "eu.stardata.server.core.formular.FormularSessionBean" String MANAGER_NAME = "managerFormular". Diese Variable ist für die Verwendung der Manager-Klasse (siehe Kapitel 3.4) wichtig. String EAR_NAME = "efp". Diese Variable bekommt den Wert aus der Konfigurationsdatei und wird in der XML Persistenz-Datei verwendet (siehe Kapitel 3.2.2). Ein Beispiel für ein Session Bean Interface als „Remote“: package eu.stardata.client.core.formular.bci; import eu.stardata.core.form.dataif.CoRuletypeDataIf; … import eu.stardata.core.form.dataif.CoRulefieldDataIf; import javax.ejb.Remote; import java.lang.String; import eu.stardata.core.form.dataif.CoFormularDataIf; import eu.stardata.server.common.exception.PersistenceException; import eu.stardata.core.form.dataif.CoExecDataIf; @Remote public interface FormularBci { // Client interface Fields public final static String JNDI_NAME = "eu.stardata.server.core.formular.FormularSessionBean"; public final static String MANAGER_NAME = "managerFormular"; public final static String EAR_NAME = "efp"; // Session - Client interface methods public void clearExec() throws PersistenceException; public CoFieldDataIf createField(CoFieldDataIf arg) throws PersistenceException; public CoFieldDataIf[] findAllField() throws PersistenceException; … public CoElementDataIf createElement(CoElementDataIf arg) throws PersistenceException; public void clearWebstyle() throws PersistenceException; } TLGen 48 StarData GmbH V 2.8 Listing 27: Session Bean Interface 3.2.2 XML Persistente Datei Ab EJB 3 ist nur eine XML Datei für ein Deployment Description notwendig. Alle anderen Dateien der Vorversionen werden entweder abgeschafft oder als Annotation verwendet. Zusätzlich gibt es noch eine XML Datei „orm.xml“ für das Mapping für Version 3 von EJB, doch diese wird wegen der Performance mit TLGen nicht benützt. TLGen erlaubt das Mapping direkt im generierten Java Code und zwar in den Entity Beans (siehe Kapitel 3.5 sowie 4.4.2.5). In der Datei „persistence.xml“, die für jede Session Bean generiert wird, sind folgende Informationen automatisch enthalten: In Tag „persistence-unit“ die Parameter name ManagerName Variable und Transaction-type In Tag „jta-data-source“ die Data Source im Format, welche der jeweilige Applikation Server benötigt (jede mit eigenem Format) Eine vollständige Liste von allen in der Applikation vorhandenen Entity Beans mit vollständig definierten Namen In Tag „propertie“ allgemeine Informationen für den Application Server Ein Beispiel für eine generierte „persistence.xml“: <?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> <persistence-unit name = "managerFormular" transaction-type = "JTA"> <jta-data-source>java:/efpPool</jta-data-source> <class>eu.stardata.server.core.user.entity.UserEntity</class> <class>eu.stardata.server.core.hlp.entity.OperationEntity</class> <class>eu.stardata.server.core.hlp.entity.FormatEntity</class> <class>eu.stardata.server.core.hlp.entity.KeyEntity</class> <class>eu.stardata.server.core.formular.entity.FieldEntity</class> <class>eu.stardata.server.core.hlp.entity.FieldtypeEntity</class> ……………………………………………….. <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/> </properties> </persistence-unit> </persistence> Listing 28: Persisitence XML In der Datei „persistence.xml“ können einige Informationen, vom Applikation Server benötigt, (in einer „properties“ Tag) definiert werden. Hinweis: Für den Applikation Server „JBoss“ Version 5 sollte die Oracle Datenbank in Version 10 benutzt werden, da diese Version von „JBoss“ noch nicht die Oracle Version erkennt! TLGen 49 StarData GmbH V 2.8 3.2.3 Interface-Klassen zu Fachlogik(Bussiness logic)-Komponenten Innerhalb einer Session Bean kann bzw. können eine oder mehrere Klassen definiert werden, die zu oder von anderen Systemen gehören bzw. aufgerufen werden oder für die Kodierung reiner Fachlogik benötigt werden. Wurden diese einmal generiert, lässt der Generator es zu, diese dort abzuspeichern, um den dort manuell entwickelten Code nicht zu löschen. Nach unserer Erfahrung ist es weder produktiv noch notwendig generierten Code mit selbst entwickelten zu mischen (merging). Daher ermöglicht TLGen eine vollständige Trennung dieser Code-Arten. 3.2.4 Interceptors Ein Interceptor ist eine einfache Java Klasse deren Methoden immer dann aufgerufen werden, wenn Session Bean-Methoden benützt werden. Die Interceptoren sind Klassen, die eigentlich zum Beispiel unter anderem zur Überwachung einer Session Bean, Übernahme der Informationen-Protokollierung oder für die Zeitmessung gedacht sind. Diese Java Klassen können über die Konfigurationsdateien in den generierten Code eingebettet werden. Es können entweder selbst geschriebene Klassen sein oder die, welche von TLGen Default-Interceptoren zur Verfügung gestellt werden. Einfaches Bespiel von einer Interceptor-Klasse für die Zeitmessung (siehe Listing 29): public class TimeFormular { // Session annotations and fields for interceptor /** * Default Constructor */ public TimeFormular() { super(); } // Session class methods /** * Interceptor method "timeTrace()" * @param invocation * @return * @throws PersistenceException */ @AroundInvoke public java.lang.Object timeTrace(InvocationContext invocation) throws PersistenceException { long start = 0; boolean toTime = true; try { if(toTime) { start = System.currentTimeMillis(); } return invocation.proceed(); TLGen 50 StarData GmbH V 2.8 } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex,1); } Finally { if(toTime) { // Example to time long ende = System.currentTimeMillis(); String klasse = invocation.getTarget().toString(); String methode = invocation.getMethod().getName(); System.out.println(klasse + ":" + methode + " -> " + (ende - start) + "ms"); } } } } Listing 29: Interceptor 3.2.5 Generierung der REST-Schnittstelle Um eine REST-Schnittstelle zu generieren, muss ein <Design> mit dem Attribute archive=“3“ angelegt werden. In der Tag <Session> wird das Attribute sessionType="REST" gesetzt und dadurch wird automatisch eine Application-Klasse mit generiert. Diese verwendet standardmäßig das Attribute „appPath“ als Namenzusatz. Da appPath=““ als konformer Application Pfad „/“ auch verwendet wird, wird der Designname als Namenzusatz verwendet. Das Attribute „restPath“ gibt den Pfad der Session Beans an. URL-Erstellung: Eine URL, wie folgt, wird folgendermaßen erstellt: http://DOMAIN/<War path>/<Application path>/<Sessionbean path> “War path” in <Design pathToGenerate="warname" > „Application path“ in <Session appPath="appname" > „ Sessionbean path“ in <Session restPath="sessionname" > Um den Bsp.-Pfad http://DOMAIN/rest/service zu generieren, sollte z.B. <Design pathToGenerate="rest" > <Session appPath="" restPath="service" > Rest-Methoden: Es gibt 2 Generierungsarten von Rest-Methoden, die automatische (mit Voreinstellungen) und die genauer einstellbare. Methode 1: Diese Methode verwendet den Methoden-Namen automatisch, um den Pfad festzulegen z.B.(siehe Listing 30) <Method name="updateWorkOrder" return="java.util.List&#60;de.test.business.service.WorkOrderJSon&#62;" client="Rest" rest="PUT" methodtype="0"> <Exception name="java.lang.Exception"/> <Parameter value="Path" name="workorderid" type="java.lang.Long"/> <Parameter value="Query" name="customerid" type="java.lang.Long"/> TLGen 51 StarData GmbH V 2.8 <Parameter name="data" type="de.test.business.service.WorkOrderJSon" /> </Method> Listing 30: REST-Methode in der Konfigurationsdatei Pfad: http://DOMAIN/rest/service/updateWorkOrder Folgende REST-Typen generieren weitere Annotationen automatisch dazu: Typ GET: Generiert automatisch die Annotation @Produces("application/json") Typ DELETE: Generiert automatisch die Annotation @Produces("application/json") Typ PUT: Generiert automatisch die Annotationen @Produces("application/json"), @Consumes ("application/json") Typ POST: Generiert automatisch die Annotation @Produces("application/json") Damit dies auch mit der zuvor genannten Methode funktioniert, muss der letzte Parameter des Methoden-Tags der „Consumer“ sein. Der “Producer” ist im Attribute „return“ festgelegt: <Parameter name="data" type="de.test.business.service.WorkOrderJSon" /> Die Methode wird folgendermaßen generiert (siehe Listing 31): @PUT @Path("/updateWorkOrder/{workorderid}/") @Produces("application/json") @Consumes("application/json") public List<WorkOrderJSon> updateWorkOrder( @PathParam("workorderid") java.lang.Long workorderid, @QueryParam("customerid") java.lang.Long customerid, WorkOrderJSon data) throws Exception; Listing 31: REST Methode Parameter Der vollständige Pfad der Applications-Methode ist dann z.B.: http://DOMAIN/rest/service/updateWorkOrder/1 Die Parameter-value sind „Query“ oder „QueryParam“ für @QueryParam und „Path“ oder „PathParam“ für @PathParam (Die Abkürzungen gelten nur für diese beiden sowie für Methode 2). Method 2: Diese Methode ermöglicht, die Pfade und alle Tags genau zu definieren. Hier ist es wichtig, das Annotations-Typen und Libs, welche nicht standardmäßig bekannt sind, mit dem vollständigen Namen anzusprechen. Um diese Methode zu verwenden, muss man nur eine Annotation mit name=“Path“ definieren. Oben genanntes Beispiel ist folgendermaßen dann definiert (siehe Listing 32): <Method name="updateWorkOrder" return="java.util.List&#60;de.test.business.service.WorkOrderJSon&#62;" client="Rest" rest="PUT" methodtype="0"> <Exception name="java.lang.Exception"/> <Annotation name="Path" value="workorder/{workorderid}/"/> <Annotation name="Produces" value="application/json"/> <Annotation name="Consumes" value="application/json"/> <Parameter value="PathParam" content="workorderid" name="workorderid" type="java.lang.Long"/> TLGen 52 StarData GmbH V 2.8 <Parameter value="QueryParam" name="customerid" type="java.lang.Long"/> <Parameter name="data" type="de.test.business.service.WorkOrderJSon" /> </Method> Listing 32: REST-Annotations und Parameter in der Konfigurationsdatei Wobei der Pfad hier @Path("/workorder/{workorderid}/") ist. Freie Annotationen und Parameter: Um eine freie Annotation @org.jboss.resteasy.annotations.providers.jaxb.XmlHeader zu erhalten, genügt folgender Parameter: <Annotation name="org.jboss.resteasy.annotations.providers.jaxb.XmlHeader"/> Um eine Klasse als value zu erhalten, muss diese im Attribute „type” definiert werden, z.B.: @Consumes(MediaType.APPLICATION_ATOM_XML) mit <Annotation type="Consumes" type="MediaType.APPLICATION_ATOM_XML" /> da im Attribute value, der String mit Hochkomma eingefügt wird. Auch freie Parameter sind nun erlaubt: Beispiel Listing 33: <Method name="createUnit" return="de.test.business.unit.UnitJSon" client="Rest" rest="POST" methodtype="0"> <Exception name="java.lang.Exception"/> <Annotation name="Path" value="unit/{unitid}/"/> <Annotation name="org.jboss.resteasy.annotations.providers.jaxb.XmlHeader" type="MediaType.APPLICATION_ATOM_XML"/> <Annotation name="Produces" value="application/json"/> <Annotation name="Consumes" value="application/json"/> <Parameter value="CookieParam" content="id" name="sessionid" type="javax.ws.rs.core.Cookie"/> <Parameter value="PathParam" content="unitid" name="unitid" type="java.lang.Long"/> <Parameter value="QueryParam" name="imei" type="java.lang.String"/> <Parameter value="QueryParam" name="customerid" type="java.lang.Long"/> <Parameter name="data" type="de.test.business.unit.UnitJSon"/> </Method> @POST @Path("/unit/{unitid}/") @XmlHeader(MediaType.APPLICATION_ATOM_XML) @Produces("application/json") @Consumes("application/json") public UnitJSon createUnit( @CookieParam("id") Cookie sessionid, @PathParam("unitid") java.lang.Long unitid, @QueryParam("imei") String imei, @QueryParam("customerid") java.lang.Long customerid, UnitJSon data) throws Exception; Listing 33: REST Beispiel 3.2.5.1 Client-Seite TLGen 53 StarData GmbH V 2.8 Zu den REST-Services werden auch automatisch JUnit-Client-Testmethoden hinzugeneriert. Falls „Consumer“ bekannt ist, werden diese automatisch mitgeneriert (dafür wird für JSON die Gson google jar benötigt). Ein einfacher HTTPClient wird mitgeneriert. Dieser ist einfach für weitere Header-Aurufe erweiterbar, um z.B. mittels eines Server-Interceptors die REST-Calls mit einem REST-Auth abzufangen und zu überprüfen. Ein Beispielcode dazu (siehe Listing 34): System.out.println("----------- testupdateRoutings() -----------"); // Initialise input parameters Gson gson0 = new GsonBuilder().setDateFormat(DATE_FORMAT).create(); RoutingJSon json0 = new RoutingJSon(); json0.setEndDate(new Date(System.currentTimeMillis())); json0.setStartDate(new Date(System.currentTimeMillis())); json0.setRoutingID(3L); json0.setNextDestinationSite("4473"); json0.setModifyDate(new Date(System.currentTimeMillis())); //fill the values for methods //json0.setUnit(de.test.business.unit.UnitJSon); List<RoutingJSon> list = new ArrayList<RoutingJSon>(); list.add(json0); String strJSon = gson0.toJson(list); // REST call String strContent = "/?customerid=3"; String strResponse = this.getHttpClient("PUT","http://localhost:8080/rest/service/routing" + strContent,"application/json",strJSon); // print return data if(strResponse != null) { System.out.println("strResponse :" + strResponse); } else { System.out.println("ReturnObject is null !!!"); } Listing 34: REST-calls vom Client 3.3 Clients, BCI (Business Common Interface) Auf der Client -Seite befindet sich das User Interface, mit dem dieser die Applikation aufrufen kann. Auf dem Server hingegen befindet sich die Applikation-Logik mit dem benötigten Code. TLGen generiert vollständig die Klassen, welche für die Kommunikation zwischen Client und Server notwendig sind. Für den Client generiert TLGen auch die Test-Klassen (auf Basis von JUnit), die für die Applikation-Tests benötigt werden. Beispiel für einen generierten Server-Aufruf (siehe Listing 35), um einen Satz in einer Datenbank abzuspeichern: CoFormularDataIf clFormular = getFormularObject(); // make a factory client for call the session bean FormularBci factory = FormularBciFactory.getFormularBci(); TLGen 54 StarData GmbH V 2.8 // call the session bean method over the client factory clFormular = factory.createFormular(clFormular); Listing 35: Server Remote Call Dieser Serveraufruf ist wie folgt durchzuführen: Zuerst ruft man die notwendige Factory (diese entspricht in der Regel einer bestimmten Session Bean auf der Serverseite) und danach mit Hilfe der Factory die gewünschte Methode auf. Im oberen Beispiel wird die Abspeicherung in der Datenbank eines Formular-Objekts dargestellt. TLGen generiert zwei Klassen/Interfaces, die diese Aufgabe erfüllen. In unserem Beispiel die Klasse FormularBciFactory.java und das Interface FormularBci.java, Teil des generierten Codes für die Factory: /** * getFormularBci() */ public static synchronized FormularBci getFormularBci() throws PersistenceException { return (FormularBci)getBciImplementation(FormularBci.class); } Listing 36: Client Class Als auch für die Interfaces: @Remote public interface FormularBci { // Client interface Fields public final static String JNDI_NAME = "eu.stardata.server.core.formular.FormularSessionBean"; public final static String MANAGER_NAME = "managerFormular"; public final static String EAR_NAME = "efp"; … public CoFormularDataIf createFormular(CoFormularDataIf arg) throws PersistenceException; … } Listing 37: Client Interface 3.3.1 Test-Klassen TLGen kann Test-Klassen (JUnit) generieren. Diese können gändert werden und sind als Hilfe für die Realisierung eines Test-Konzeptes gedacht. TLGen generiert für die gewünschten Aufrufe die kompletten Test-Klassen mit generierten TestWerten oder aus einer Daten-Datei die geladenen Test-Daten. Für welche Aufrufe die TestKlassen (JUnit) zu generieren sind, soll in der Konfigurationsdatei eingetragen werden (für weitere Details siehe Kapitel 4.5.2.4.8). TLGen 55 StarData GmbH V 2.8 Test-Klassen kann man testen und die Ergebnisse in einer Datei printen oder direkt auf den Bildschirm ausgeben (z. B. in Eclipse). Auch kann man diese im JUnit, wo sie mit Hilfe der Asset-Methode zur Verfügung gestellt werden, ersehen. Listing 38 zeigt ein Beispiel für eine Test-Klasse: public class FormularWriteReadTest extends TestCase { private static final long serialVersionUID = 435512065; // Test class data fields private static CoFormularDataIf m_clFormular = null; /** * Default Constructor */ public FormularWriteReadTest() { super(); // Insert your configuration data for application server de.stardata.base.config.InitProgramm.put(de.stardata.base.config.ConfigKeyNames.INITIAL_CONTEXT,"jn p://localhost:9099"); de.stardata.base.config.InitProgramm.put(de.stardata.base.config.ConfigKeyNames.INITIAL_CONTEXT_F ACTORY,"org.jnp.interfaces.NamingContextFactory"); de.stardata.base.config.InitProgramm.put(de.stardata.base.config.ConfigKeyNames.INITIAL_PKG_PREFIX ES,"org.jboss.naming:org.jnp.interfaces"); } // Test class methods /** * Test method "testCreateFormular()" */ public void testCreateFormular() { try { m_clFormular = new CoFormularData(); // initialize data for test class m_clFormular.setCoreId(3); …………………………………………………………………….. m_clFormular.setLanguage(writeLanguage()); m_clFormular.setMandant(writeMandant()); // make a factory client for call the session bean FormularBci factory = FormularBciFactory.getFormularBci(); // call the session bean method over the client factory m_clFormular = factory.createFormular(m_clFormular); // print the new primary key System.out.println("New primary key is = " + m_clFormular.getFormularId()); } catch(PersistenceException ex) { ex.printStackTrace(); } } Listing 38: Test-Klasse - Beispiel 3.3.1.1 Attribute für <Test> Tag Annotation Für Test-Klassen können mehrere Attribute verwendet werden, um so die Generierung zu steuern (siehe Tabelle 4). TLGen 56 StarData GmbH V 2.8 Tabelle 4: Attribute für <Test> Tag-Annotation Attributen Default Name nein Kommentar Test-Klasse Name mit vollem path sessionType ja Generiert folgende Test-Klassen Typen: „Session“ ist eine normale Test-Klasse für eine Remote Verbindung und „REST“, generiert eine Client Test-Klasse für ein REST call client nein Definiert den Namen des Clients type ja public (ist default), protected oder private 3.3.1.2 Verwendung von Test-Daten aus externen Dateien Mit Hilfe der Konfigurationsdateien kann man eine XML Datei generieren, welche die Datenstruktur einer oder mehrerer Test-Objekte nachbildet. Diese XML kann mit den gewünschten Daten erweitert und für Tests genutzt werden. Diese Datei wird in Listing 39: Externe TestDaten4 dargestellt. <?xml version="1.0" encoding="UTF-8"?> <TestMethod xsi:noNamespaceSchemaLocation = "C:/Project-TLGen-2.1/source/generated/TestDataSchema.xsd" name = "testCreateFormular" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" type = "void"> <Variable name = "FormularId" value = "2" type = "long"/> <Variable name = "CoreId" value = "2" type = "long"/> ……………………………………………………………………………………………….. <Variable name = "Document_id" value = "2" type = "long"/> ………………………………………………………………………………………………. <Method name = "writeMandant" type = "eu.stardata.core.cor.dataif.CoMandantDataIf"> <Variable name = "MandantId" value = "4" type = "long"/> ……………………………………………………………………………………………….. <Variable name = "Code" value = "-628" type = "java.lang.String"/> </Method> </TestMethod> Listing 39: Externe Test-Daten Die verwendete Schema-Datei “TestDataSchema.xsd” hat folgende Struktur: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!--W3C Schema generated by XMLSpy v2009 (http://www.altova.com)--> <!--Please add namespace attributes, a targetNamespace attribute and import elements according to your requirements--> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:import namespace="http://www.w3.org/XML/1998/namespace"/> <xs:element name="Variable"> <xs:complexType> <xs:attribute name="name" use="required" type="xs:anySimpleType"/> <xs:attribute name="type" type="xs:anySimpleType"/> <xs:attribute name="value" type="xs:anySimpleType"/> </xs:complexType> </xs:element> <xs:element name="Type"> TLGen 57 StarData GmbH V 2.8 <xs:complexType mixed="true"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="Variable"/> <xs:element ref="Type"/> <xs:element ref="Enum"/> </xs:choice> <xs:attribute name="name" use="required" type="xs:anySimpleType"/> <xs:attribute name="type" type="xs:anySimpleType"/> </xs:complexType> </xs:element> <xs:element name="TestMethod"> <xs:complexType mixed="true"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="Variable"/> <xs:element ref="Method"/> <xs:element ref="Type"/> <xs:element ref="Enum"/> </xs:choice> <xs:attribute name="name" use="required" type="xs:anySimpleType"/> <xs:attribute name="type" type="xs:anySimpleType"/> </xs:complexType> </xs:element> <xs:element name="Method"> <xs:complexType mixed="true"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="Type"/> <xs:element ref="Enum"/> <xs:element ref="Variable"/> <xs:element ref="Method"/> </xs:choice> <xs:attribute name="name" use="required" type="xs:anySimpleType"/> <xs:attribute name="type" type="xs:anySimpleType"/> </xs:complexType> </xs:element> <xs:element name="Enum"> <xs:complexType> <xs:attribute name="name" use="required" type="xs:anySimpleType"/> <xs:attribute name="type" type="xs:anySimpleType"/> <xs:attribute name="value" type="xs:anySimpleType"/> </xs:complexType> </xs:element> </xs:schema> Listing 40: XML Schema für externe Test-Daten 3.3.1.3 “Junit” Test-Klasse für “REST”-calls Siehe Kapitel 3.2.5.1 3.4 Entity Manager-Klasse Eine Entity Manager-Klasse ist eine lokale Stateless Session Bean, die für die Steuerung der Persistenz (Entity Bean) genutzt wird. Entity Manager-Klassen können Default-Methoden für Datenbank-Administration für CRUD sein oder aber auch Datenbank-Zugriffsmethoden, generiert auf Basis von selbst geschriebenen SQL’s. In Tabelle 5 sind die Default-Methoden, welche TLGen automatisch generieren kann: TLGen 58 StarData GmbH V 2.8 Tabelle 5: Automatisch generierbare Default-Methoden im Entity Manager Nr. Method Name Parameter Return Funktionalität 1 create“Name“ Objekt Objekt Speichern eines neuen Objekts in der Datenbank 2 update“Name“ Objekt void Aktualisieren eines Objekts seine Kinder in der Datenbank und 3 remove“Name“ Object - Löschen eines Datenbank der 4 flusch“Name“ Object - Beenden des Vorgangs 5 close“Name“ - - Schließt ein Entity Objekt ein 6 clear“Name“ - - 7 findByPrimaryKey“Name“ Object PK 8 findAll“Name“ 9 mit Objekts in Object Lesen eines Objekts aus DB mit dem PK - Object[] Lesen aller abgespeicherten Objekte findBy“Name“ Parameter List Object[] Lesen aller Parameter List 10 deleteBy“Name“ Parameters, level int Löschen aller Daten (Zeile in der betroffenen Tabelle) in der Datenbank für die eingegebenen Parameter. Falls für diese Entity Bean auch Links existieren, werden auch diese alle gelöscht 11 detach Object void Detach Methode 12 readUpdate Object - Lesen des Objekts ID, dann update dieses Objekts in Database 13 fullUpdate Object - Zuerst werden die Daten aus der Datenbank gelesen, dann erfolgt die Aktualisierung der Daten mit all seinen Kindern (OtO, OtM, OtO MtM) in der Datenbank 14 getEntityManager - EntityManager Übernimmt die “javax.persistence.EntityMnager” local Variable 15 getManager Object Object Übernimmt eine instance aus der Entity Manager-Klasse Objekte für die Ein Beispiel für generierten Code aus Fehler! Verweisquelle konnte nicht gefunden werden., Zeile 9 ist in Listing 41 dargestellt: TLGen 59 StarData GmbH V 2.8 public class ProductManager extends BaseManager implements ProductBciIf { private String m_getNameAndOffer = "select u from ProductEntity u where u.name = :name and u.productOfferingId = :productOfferingId"; ……………………………………………………………… /** * Manager method "findByNameAndOffer()" * @param name * @param productOfferingId * @return * @throws PersistenceException */ public ProductDataIf[] findByNameAndOffer(String name, String productOfferingId) throws PersistenceException { try { ProductDataIf[] listData = null; List<?> list = m_manager.createQuery(m_getNameAndOffer).setParameter("name", name).setParameter("productOfferingId",productOfferingId).getResultList(); if(list != null && list.size() > 0) { listData = new ProductDataIf[list.size()]; int idx = 0; for(Object entity : list) { if(entity != null) { listData[idx++] = ((ProductEntity)entity).callProduct(); } } } return listData; } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex,1); } } ……………………………………………………………….. } Listing 41: “Find by name” Method Das Lesen, Abspeichern oder Löschen von Objekten kann direkt im Aufruf gesteuert werden, ob nur das „Vater“ Objekt gelesen, gespeichert oder gelöscht wird oder aber dieser zusammen mit seinen „Kindern“ (solange die Beziehungen zwischen diesen „Null“ akzeptiert). Für das selbst geschriebene SQL bietet TLGen eine Fülle von Modellen an, die sehr einfach in der Konfigurationsdatei zu nutzen sind, mit der letztendlich TLGen den entsprechenden Code generiert. In der Regel ist es nur sehr selten notwendig ein solches SQL zu schreiben, weil durch automatisches Einbeziehen von Relationen alle benötigten Objekte gelesen und abgespeichert werden. Es folgt ein Ausschnitt einer generierten Manager-Klasse (siehe Listing 42): package eu.stardata.server.core.formular.manager; import javax.persistence.EntityManager; ……………………………………………….. import javax.ejb.Local; @Stateless(name = eu.stardata.server.core.formular.bci.FormularBci.JNDI_NAME) @Local(eu.stardata.server.core.formular.bci.FormularBci.class) TLGen 60 StarData GmbH V 2.8 public class FormularManager extends BaseManager implements eu.stardata.server.core.formular.bci.FormularBci { private static final long serialVersionUID = 644414680; // Manager class data fields @PersistenceContext(unitName = FormularBci.MANAGER_NAME) public EntityManager m_manager = null; private String m_getName = "select o from FormularEntity o where o.formular = :formular"; private String m_SQL_FIND_ALL = "select o from FormularEntity o"; ………………………………………………………………… /** * Manager method "findByPrimaryKey()" * @param arg * @return * @throws PersistenceException */ public CoFormularDataIf findByPrimaryKey(CoFormularDataIf arg) throws PersistenceException { try { CoFormularDataIf classData = null; FormularEntity entity = m_manager.find(FormularEntity.class, arg.getFormularId()); if(entity != null){ classData = entity.callFormular(); } return classData; } catch(Exception ex){ throw new PersistenceException(ex.getMessage(),ex,1); } } ………………………………………………. } Listing 42: “Find by Primary Key” Method Alle in den Manager-Klassen verwendeten Methoden können von den dazugehörigen Session Beans übernommen werden oder auch nicht. Dies kann über die Konfigurationsdatei gesteuert werden (Default bedeutet, dass alle übernommen werden). In Tabelle 6 sind die Annotationen, die für eine Manager-Klasse verwendet werden. Tabelle 6: Annotationen für Entity Manager-Klasse Annotationen Vervendung inTLGen Kommentar Stateless ja Bezeichnet eine Session Stateless Bean Local ja Ist nur lokal zu verwenden PersistenceContext ja Definiert den Manager-Name 3.4.1 Methoden im Entity-Manager In der generierten Entity Manager-Klasse werden auch zahlreiche Methoden generiert, notwendig für den Datenbankzugriff. Die Generierung dieser Methoden wird in der „config“-Datei eingetragen und ist für die SQL Typen „named“ und „native“ gültig. Folgende Methoden sind generierbar: Automatisch generierte Methoden (siehe Tabelle 5) Methodtype=6, für die Verwendung von„Named“ SQL(siehe Listing 43) TLGen 61 StarData GmbH V 2.8 Methodtype=7, für die Verwendung g von„Named“ SQL Methodtype=8, für die Verwendung von „Native“ SQL (siehe Listing 4444) Methodtype= , für die Criteria Aufrufe. In diesem Fall wird auch der Link zu einer Klasse, in welcher der Programmierer sein Java Code eingebaut hat, generiert (siehe Listing 45) Eintrag in der „config“ Datei: <Method name="findHistoryCustomer" return="java.util.List&#60;%interfacedata%&#62;" manager="HistoryCustomer" methodtype="6"> <Parameter name="customer" type="Object" /> <Sql name="getHistoryCustomer" sql="select o from HistoryCustomerEntity o where o.customer = :customer"/> </Method> Und der generierte Code: public List<HistoryCustomerData> findHistoryCustomer(Object customer, int level) throws PersistenceException { try { List<HistoryCustomerData> list = null; List<?> entityList = m_manager.createQuery(m_getHistoryCustomer).setParameter("customer",customer).getResultList(); if(entityList != null && entityList.size() > 0) { list = new ArrayList<HistoryCustomerData>(); for(Object entity : entityList) { if(entity != null) { list.add(((HistoryCustomerEntity)entity).callHistoryCustomer(level)); } } } return list; } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } Listing 43: SQL Named Beispiel Eintrag in “config” datei: <Method name="NativeQuery00" manager="Customer" mapping="true" methodtype="8"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Sql sql="SELECT * FROM Customer WHERE Customer_ID = ?" /> </Method> Und das generierte code: public List<NativeQuery00Data> NativeQuery00(long Customer_id, int level) throws PersistenceException { try { List<NativeQuery00Data> list = null; List<?> entityList = m_manager.createNativeQuery(m_NativeQuery00,"NativeQuery00").setParameter(1,Customer_id).getResultList(); if(entityList != null && entityList.size() > 0) { list = new ArrayList<NativeQuery00Data>(); for(Object entity : entityList) { if(entity != null) { NativeQuery00Data data = new NativeQuery00Data(); if(entity instanceof CustomerEntity) { data.setCustomer(((CustomerEntity)entity).callCustomer(level)); } list.add(data); } TLGen 62 StarData GmbH V 2.8 } } return list; } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } Listing 44: SQL Native Beispiel Eintrag in “config” datei: <Method name="countTestServices" return="java.lang.Long" criteria="true" manager="Customer" methodtype="11"> <Parameter name="corporateId" type="java.lang.Long" /> <Parameter name="service" type="java.lang.String" /> <Parameter name="statusEnumFilterMatrix" type="java.util.List&#60;java.util.List&#60;java.lang.Enum&#60;?&#62;&#62;&#62;"/> </Method> Und der generierte code: public Long countTestServices(java.lang.Long corporateId, String service, List<List<Enum<?>>> statusEnumFilterMatrix) throws PersistenceException { try { CustomerCriteria criteria = new CustomerCriteria(); return criteria.countTestServices(m_manager, corporateId, service, statusEnumFilterMatrix); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } Listing 45: Criteria Beispiel Der Inhalt einer Criteria-Methode wird in eine Klasse ausgelagert, die auch von TLGen auf ein Path, eventuell definiert in den <Project> , generiert wird (siehe 4.5.2.2). Die Fachlogik für diesen Zugriff wird manuell mit Hilfe von Meta-Klassen geschrieben (siehe 3.5.2). In Listing 45 ist diese Klasse „eu.stardata.test.persistence.CustomerCriteria“ mit der Methode „countTestService()“ und folgenden Parametern: m_manager ist das „javax.persistence.EntityManager“ und ist für die Verwendung in Criteria API (z. B. Verwendung von „CriteriaBuilder“) notwendig corporateId ist ein Arbeitsparameter service ist ein anderer Parameter Diese Methode ergibt ein Ergebnis, welches im Programm verwendet werden kann. 3.4.2 Entity Manager-Interfaces Weil Manager Klassen eigentlich lokale Session Beans sind, benötigen sie ein eigenes Interface. Diese werden auch automatisch von TLGen generiert. Beispiel für ein Interface einer Manager-Klasse (Listing 46): TLGen 63 StarData GmbH V 2.8 import eu.stardata.core.form.dataif.CoFormularDataIf; import java.lang.String; import eu.stardata.server.common.exception.PersistenceException; import eu.stardata.server.core.formular.bci.FormularBci; import eu.stardata.server.core.formular.entity.FormularEntity; public interface FormularBci { // Manager interface data fields public String JNDI_NAME = "eu.stardata.server.core.formular.bci.FormularBci"; public String EAR_NAME = "efp"; // Manager interface methods public CoFormularDataIf findByPrimaryKey(CoFormularDataIf arg) throws PersistenceException; … public void close() throws PersistenceException; } Listing 46: Entity Manager Interface Beispiel 3.5 Entity Beans Die Entity Beans sind das Tor zur Datenbank, besser gesagt, sie sind die Schnittstellen für eine relationale Datenbank. Eine Entity Bean sollte einer Tabelle in der Datenbank entsprechen und so eine saubere sowie strukturierte Architektur für die Persistenzschicht ermöglichen. Das ist von großer Bedeutung für die Code-Wartung als auch für weitere Entwicklungen. Entity Beans sind seit EJB3 POJO’s (Old Java Objects, darum auch nicht mehr Entity Beans genannt) normale Java-Klassen und anders als die Session Beans, denn sie brauchen keine Interfaces. Jede Entity Bean muss einen Standardkonstruktor besitzen, weil es unter anderem Aufgabe einer Manager-Klasse ist, eine Instanz für die Entity Bean zu erzeugen. TLGen generiert in einer Entity Bean die notwendigen Annotationen, Variablen, Default-Konstruktor, Mapping Methoden zwischen Daten-Objekt Attributen, Tabellenspalten, einige Hilfsmethtoden, die diese Mapping unterstützen sowie die Methoden für die Relationen. Für eine Entity Bean werden auch mehrere Annotationen und Variablen generiert wie in Listing 47 dargestellt: package eu.stardata.server.core.formular.entity; import javax.persistence.GeneratedValue; ………………………………………………………………….. import javax.persistence.Entity; @Entity @Table(name="CORE_FORMULAR") @SequenceGenerator(name="SEQ_STORE_FORMULAR", sequenceName="CORE_FORMULAR_SEQ", initialValue=1, allocationSize=20) public class FormularEntity { private static final long serialVersionUID = 802995295; // Entity data field private CoFormularDataIf m_formular = null; // Fields from relations tables TLGen 64 StarData GmbH V 2.8 private List<PageEntity> m_page = new ArrayList<PageEntity>(); private List<DocumentlistEntity> m_documentlist = new ArrayList<DocumentlistEntity>(); private LanguageEntity m_language = null; … // constructors /** * Default Constructor */ public FormularEntity() { } /** * Constructor * @param arg */ public FormularEntity(CoFormularDataIf arg) { m_formular = arg; fillFormular(); } // Helper methods /** * Helper Method "makeFormular" */ public CoFormularDataIf makeFormular() { if(m_formular == null) { m_formular = new eu.stardata.core.form.data.CoFormularData(); } return m_formular; } … } Listing 47: Entity Bean In Tabelle 7 sind die Annotationen dargestellt, die für Entity Beans von EJB3 vorgesehen sind: Tabelle 7: Annotationen für Entity Beans (EJB3) Annotationen Vervendung inTLGen Kommentar Entity ja Definiert eine Entity Bean Table ja Tabelle, die zu einer Entity gehören Column ja Spalte einer Tabelle (für Mapping) SequenceGenerator ja Definiert die Art von Sequence-Generator GeneratedValue ja Generiert eine Sequence (für die automatische Generierung von ID‘s) Id ja Definiert eine PK ManyToMany ja Relation Typ (siehe 2.6.1.4 und 4.5.3.8) ManyToOne ja Relation Typ (siehe 2.6.1.2 und 4.5.3.8) OneToMany ja Relation Typ (siehe 2.6.1.1 und 4.5.3.8) OneToOne ja Relation Typ (siehe 2.6.1.3 und 4.5.3.8) Version ja Verwendet für die Versionskennzeichnung, wird für Locking verwendet TLGen 65 StarData GmbH V 2.8 PostLoad ja Hilfsmethoden, welche vor oder nach Processing aufgerufen werden PostPersist ja Hilfsmethoden, welche vor oder nach Processing aufgerufen werden PostRemove ja Hilfsmethoden, welche vor oder nach Processing aufgerufen werden PostUpdate ja Hilfsmethoden, welche vor oder nach Processing aufgerufen werden PrePersist ja Hilfsmethoden, welche vor oder nach Processing aufgerufen werden PreRemove ja Hilfsmethoden, welche vor oder nach Processing aufgerufen werden PreUpdate ja Hilfsmethoden, welche vor oder nach Processing aufgerufen werden JoinColumn ja Verbindungsspalte für eine Relation JoinColumns ja Mehrzahl von Verbindungsspalten JoinTable ja Verbindung DB Tabelle für eine ManyToMany Relation Embeddable ja Für komplexe Primary Key verwendet NamedQuery ja Definiert eine named SQL Query NamedNativeQuery ja Definiert eine named Native Query OrderBy ja Sortiert die Ergebnisse Enumerated nein Vorgesehen für die nächste Version EmbeddedId nein Vorgesehen für die nächste Version Transient nein Vorgesehen für die nächste Version TableGenerator nein Vorgesehen für die nächste Version Temporal nein Vorgesehen für die nächste Version Lob ja Für Blob und Clob (Große Daten) verwendet SecondaryTable nein Vorgesehen für die nächste Version Basic ja Wird zusammen mit Lob verwendet PersistenceProperty nein Vorgesehen für die nächste Version PersistenceUnit nein Vorgesehen für die nächste Version UniqueConstraint nein Vorgesehen für die nächste Version Inheritance nein Vorgesehen für die nächste Version Innerhalb einer Entity Bean generiert TLGen eine Reihe von Hilfsmethoden, die für das Mapping von Daten-Relationen notwendig sind. Diese Methoden sind: fill„Name“(), hat keine Parameter und wird im Constructor aufgerufen. Ist für das Speichern eines neuen Objekts in der Datenbank für eine “ManyToOne” Relation notwendig add„Name“(), hat keine Parameter und wird vom Manager aufgerufen. Ist für das Speichern eines neuen Objekts in der Datenbank für eine “OneToMany” Relation notwendig TLGen 66 StarData GmbH V 2.8 call„Name“(), wird für alle Relationen beim Lesen eines Objekts aus der Datenbank benutzt. Listing 48 zeigt ein Beispiel-Code an: /** * Helper Method "callFormular" */ public CoFormularDataIf callFormular() { // Relation ManyToOne, read data for "Formular" child, "Language" if(getLanguage() != null) { makeFormular().setLanguage(getLanguage().callLanguage()); } // Relation ManyToOne, read data for "Formular" child, "Mandant" if(getMandant() != null) { makeFormular().setMandant(getMandant().callMandant()); } // return the data object return makeFormular(); } Listing 48: Entity Bean “call…” Helper Methods In Listing 49 stellt ein Beispiel einer Mapping-Methode mit einem Sequence Generator für Primary Key dar: // Methods from columns @Id @Column(name = "FORMULAR_ID") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_STORE_FORMULAR") public long getFormularId() { return makeFormular().getFormularId(); } public void setFormularId(long arg) { makeFormular().setFormularId(arg); } Listing 49: Entity Bean Sequence Generator TLGen generiert auch automatisch komplex verschachtelte Aufrufe für das Mapping, Beispiel (Listing 50): @Column(name = "authentificationFirstname", length = 255) public String getAuthentificationFirstname() { if(makeUser().getAuthentification() != null && makeUser().getAuthentification().getName() != null) { return makeUser().getAuthentification().getName().getFirstname(); } return null; } public void setAuthentificationFirstname(String arg) { if(makeUser().getAuthentification() == null) { makeUser().setAuthentification(new Authentification()); } TLGen 67 StarData GmbH V 2.8 if(makeUser().getAuthentification().getName() == null) { makeUser().getAuthentification().setName(new Name()); } makeUser().getAuthentification().getName().setFirstname(arg); } Listing 50: Entity Bean (Mapping) 3.5.1 Relationen in Entity Beans Ein wichtiger Bestandteil von Entity Beans sind die Relationen zwischen verschiedene Objekte, die in einer Datenbank abgespeichert oder ausgelesen werden. In diesem Kapitel erfolgt die Beschreibung für die Verwendung von Relationen sowie des vom TLGen generierten Codes. 3.5.1.1 Relation „OneToMany“ „OneToMany“ Relation wird verwendet, wenn ein Objekt mehrere sub-objects (Kinder) besitzt. In einer Datenbank wird dieses durch eine Tabelle, die eine „OneToMany“-Relation zu einer anderen Tabelle hat, dargestellt. In das Daten-Interface wird so eine Relation durch eine Liste, wie in Listing 51, erkennbar, dargestellt: public interface CoFormularDataIf extends BaseDataIf { … public abstract List<CoPageDataIf> getPage(); public abstract void setPage(List<CoPageDataIf> arg); … } Vom “Formular” Objekt zum “Page” Objekt: { … public abstract CoFormularDataIf getFormular(); public abstract void setFormular(CoFormularDataIf arg); … } Listing 51: Entity Bean – “OneToMany” Interface und vom “Page”-Objekt zum “Formular” Objekt wie in Listing 52: // Methods from relations tables @OneToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE}, mappedBy = "formular",targetEntity = PageEntity.class) public List<PageEntity> getPage() { return m_page; } TLGen 68 StarData GmbH V 2.8 public void setPage(List<PageEntity> arg) { m_page = arg; } Listing 52: ”OneToMany” - Entiy-Bean-Methode Ob solch ein Objekt gespeichert werden muss oder nicht, hängt von der Art der Relation ab, „not null“ oder „null“. All seine Kinder werden automatisch gespeichert, wenn im Vater Objekt die Kinderdaten vorhanden sind. Der Abspeicherungsprozess von Daten erfolgt automatisch durch einen einzigen Aufruf einer „create“ Methode. Beim Lesen werden zusammen mit dem Vater auch alle seine Kinder berücksichtigt, wenn diese vorhanden sind. Die Tiefe von RelationEbenen kann gesteuert werden, d. h. es kann nur der Vater gelesen/gespeichert werden oder die Ebenen können immer weiter mit den Kindern erweitert werden. Diese Ebenenerweiterungen werden dann möglich, wenn die Art der Relationen „null“ ist. (Beispiel: ein „Formular“ hat mehrere „Pages“ und jede Page hat mehrere „Fields“ usw.). Abbildung 12: „OneToMany“-Darstellung im UML-Domainmodell Eine UML-Darstellung für so eine Relation und befindet sich in Abbildung 12. Zwischen „Formular“-Objekt und „Page“-Objekt existiert eine „null OneToMany“-Relation und zwischen „Page“-Objekt und „Fields“-Objekt eine „not null OneToMany“-Relation. Als Datenmodell im UML wird diese Relation in Abbildung 13 dargestellt. Abbildung 13: „OneToMany“-Darstelung in der Datenbank TLGen 69 StarData GmbH V 2.8 3.5.1.2 Relation „ManyToOne“ Diese Relation ist eine symmetrische Relation zu „OneToMany“, d. h. ein Objekt kann mit mehreren anderen Objekten verwendet werden. Auch bei dieser Art von Relation kann eine „not null“-Verbindung existieren und dieser Link muss immer mit Daten versorgt werden, d. h. in der Datenbank muss der Fremdschlüssel in den Kinder-Tabellen „not null“ sein (z.B. ein FK =Fremdschlüssel) , der Typ „long“ soll immer größer als 0 sein und in der Tabelle, wo FK angezeigt wird, muss ein richtiger Satz vorhanden sein Die UML-Darstellung ist gleich mit der in Abbildung 12 und das Datenmodell wie in Abbildung 13, aber die Richtung ist umgekehrt als bei der Relation „OneToMany“. Das gilt auch für die Code-Darstellung in Listing 52: ”OneToMany” - Entiy-Bean-Methode. Für den Entity Bean Code ist Listing 53: „ManyToOne“ Entity-Methode zu beachten: @ManyToOne(optional = true,targetEntity = WebstyleEntity.class) @JoinColumn(name = "WEBSTYLE_ID",insertable = true, updatable = true, nullable = true, unique = false,referencedColumnName = "WEBSTYLE_ID") public WebstyleEntity getWebstyle() { return m_webstyle; } public void setWebstyle(WebstyleEntity arg) { m_webstyle = arg; } Listing 53: „ManyToOne“ Entity-Methode 3.5.1.3 Relation „OneToOne“ Die Relation „OneToOne“ verbindet zwei Objekte so, dass eines ein einziges Kind besitzt. Auch bei dieser Relation ist eine „null“-Verbindung möglich, d. h. der Fremdschlüssel kann null oder „not null“ sein. In diesem Fall muss der Fremdschlüssel immer vorhanden sein und zu einem vorhandenen Satz in der Datenbank die Verbindung anzeigen. Auch bei dieser Verbindung gibt es einen Vater und ein Kind. Code für diese Relation ist in Listing 54 (Daten-Interfaces) und in Listing 55 für das Entity-Bean dargestellt. TLGen 70 StarData GmbH V 2.8 public interface CoFieldDataIf extends BaseDataIf { … public abstract CoTableDataIf getTable(); public abstract void setTable(CoTableDataIf arg); … } Listing 54: „OneToOne” Data-Interface public class FieldEntity { private private TableEntity m_table = null; … @OneToOne(cascade = {CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE}, targetEntity = TableEntity.class,optional = true) @JoinColumn(name = "TABLE_ID",insertable = false, updatable = false, nullable = true, unique = false,referencedColumnName = "TABLE_ID") public TableEntity getTable() { return m_table; } public void setTable(TableEntity arg) { m_table = arg; } … } Listing 55: „OneToOne” Entity Bean 3.5.1.4 Relation „ManyToMany“ Die Relation „ManyToMany“ ist die komplexe Form für das Verbinden mehrerer Objekte/Tabellen. Auf der Code-Ebene hat jedes Objekt eine Liste mit den anderen Objekten wie in Listing 56. public interface UserDataIf extends BaseDataIf { ... // Methods from relations tables public abstract List<UserRoleDataIf> getUserRole(); public abstract void setUserRole(List<UserRoleDataIf> arg); ... } Vom “User” Objekt zu “UserRole” Objekt public interface UserRoleDataIf extends BaseDataIf { ... // Methods from relations tables public abstract List<UserDataIf> getUser(); public abstract void setUser(List<UserDataIf> arg); ... } Listing 56: „ManyToMany“-Interface TLGen 71 StarData GmbH V 2.8 In der Datenbank-Ebene ist für diese Relation eine dritte Tabelle notwendig, eine so genannte Mapping Tabelle, wie in Abbildung 15. Die Darstellung in einem Domain-Modell ist in Abbildung 14 ersichtlich. Abbildung 14: „ManyToMany“-Darstellung im UML-Domainmodell Aus einem Domaimodelll generiert TLGen für „ManyToMany“-Relationen automatisch die nötige Mapping Tabelle als SQL Skript. Abbildung 15: „ManToMany“ Darstellung in der Datenbank In den Entity Beans werden Annotationen mit den dazugehörigen Methoden, wie in unserem Beispiel, sowohl in der „UserEntity“ Bean als auch in „UserRoleEntity“ Bean generiert (siehe Listing 57): @Entity @Table(name="UserTable") @SequenceGenerator(name="SEQ_STORE_USER", sequenceName="USERTABLE_SEQ", initialValue=1, allocationSize=10) public class UserEntity extends BaseData implements Serializable { // Entity data field private UserDataIf m_user = null; … // Methods from relations tables @ManyToMany(targetEntity = UserRoleEntity.class) @JoinTable(name = "UserRole_UserTable",inverseJoinColumns = {@JoinColumn(name = "UserRole_ID",insertable = true, updatable = true, nullable = false, unique = false)}, joinColumns = {@JoinColumn(name = "UserTable_ID",insertable = true, updatable = true, TLGen 72 StarData GmbH V 2.8 nullable = false, unique = false)}) public List<UserRoleEntity> getUserRole() { return m_userRole; } public void setUserRole(List<UserRoleEntity> arg) { m_userRole = arg; } … } „ManyToMany“ zwischen “User” und „UserRole“ @Entity @Table(name="UserRole") @SequenceGenerator(name="SEQ_STORE_USERROLE", sequenceName="USERROLE_SEQ", initialValue=1, allocationSize=10) public class UserRoleEntity extends BaseData implements Serializable { private static final long serialVersionUID = 413271821; // Entity data field private UserRoleDataIf m_userRole = null; … // Methods from relations tables @ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE}, mappedBy = "userRole",targetEntity = UserEntity.class) public List<UserEntity> getUser() { return m_user; } public void setUser(List<UserEntity> arg) { m_user = arg; } … } Listing 57: „ManyToMany“-Relation in Entity Bean In der Praxis haben wir 3 Möglichkeiten Tabellen zwischen denen eine „ManyToMany“ Relation existiert, abzuspeichern, wie: Speichern beider Objekte gleichzeitig. Das „User“-Objekt beinhaltet die Daten für dessen „UserRole“ und in der Datenbank werden drei Sätze gespeichert, einer in der „USERROLE“ Tabelle, der andere in die „USER“ Tabelle und der dritte Satz in Tabelle „USER_USERROLE“ mit beiden ID’s (USER_ID und USERROLE_ID). Speichern einer „UserRole“ von einem oder mehreren Objekt(en) in der „USERROLE“ Tabelle Speichern eines „User“ Objektes, der mit einem „USERROLE_ID“ einer vorhandenen „USERROLE“ versorgt wird, in dem Datenbank-Objekt einer „UserRole“. In diesem Fall werden zwei Sätze in der Datenbank gespeichert, einer in die „USER“ Tabelle und ein zweiter in der Tabelle „USER_USERROLE“ mit beiden ID’s. Falls der „USERROLE_ID“ zeigt, dass ein „USERROLE“ in dieser Tabelle nicht vorhanden ist, wird eine Exception zurück zum Client gesendet und eine Roll-Back Transaktion folgt. TLGen 73 StarData GmbH V 2.8 3.5.2 Meta-Klassen (für Criteria) Meta-Klassen werden für die Codierung von Criteria API verwendet. Man erstellt von Entity Beans ein Meta-Modell, in dem alle Klassen und Attribute mit ihren Datentypen definiert sind. Will man sich bei der Verwendung der Criteria API auf eine bestimte Spalte einer Bean beziehen, greift man dann auf dieses Meta-Modell zurück. In Listing 588 wird eine Meta Modell-Klasse dargestelt: @StaticMetamodel(CustomerEntity.class) public class CustomerEntity_ implements Serializable { private static final long serialVersionUID = 1102865432; // Meta annotations and fields public static volatile SingularAttribute<CustomerEntity,Long> customerID; public static volatile SingularAttribute<CustomerEntity,Long> ejb3Optlock; public static volatile SingularAttribute<CustomerEntity,Date> modifyDate; ……….…. public static volatile SingularAttribute<CustomerEntity,LanguageEntity> language; public static volatile ListAttribute<CustomerEntity,HistoryCustomerEntity> historyCustomer; public static volatile ListAttribute<CustomerEntity,LoginEntity> login; public static volatile ListAttribute<CustomerEntity,SubscriberEntity> subscriber; } Listing 58: Meta-Klasse - Beispiel 3.6 „Message Driven“ Bean Bestimmte Aufgaben von komplexen Anwendungen müssen nicht sofort erledigt werden, sondern können mit bestimmten Nachrichten auf einem späteren Zeitpunkt verschoben werden. Für diese Art von Aufgaben stehen im Applikation-Server die Message Driven Beans bereit. Die Kommunikation zwischen Client und Server über Message Driven Beans läuft über dem JMS (Java Message Service). TLGen kann die Message Driven Beans mit sehr wenig Aufwand generieren. Mit den generierten Message Driven Beans kann die Applikation über Callback-Klassen kommunizieren (siehe Kap. 3.8) und somit ist eine klare Trennung zwischen der technischen und der fachlichen Schicht realisierbar. Mit Hilfe der Steuerung über die Konfigurationsdateien können für die Message Driven Beans folgende Features generiert werden: TLGen 74 StarData GmbH V 2.8 Annotationen mit Parametern (Tabelle 8) Client-Klassen Message Driven Bean-Klassen Callback-Klassen für die Verbindung mit der Fachlogik-Schicht. Tabelle 8: Annotationen für „Message Driven“ Bean Annotationen Verwendung in TLGen Kommentar javax.annotation.Resource ja Definiert die Ressource der Message Driven Beans javax.ejb.MessageDriven ja Definiert ein Message Driven Bean javax.ejb.ActivationConfigProperty ja Setzt die Eigenschaften der Message Driven Beans 3.7 Services Die Applikation Server bieten für EJB 3.1 zwei Services an, „Timerservices“, mit deren Hilfe ein bestimmter Prozess zu einem bestimmten Zeitpunkt aufgerufen werden kann (periodisch wiederholbar) und „Web Services“, die Session-Beans über Internet/Intranet aufrufen können. TLGen kann beide Services generieren. 3.7.1 „Timer Service“ Ein Timer Service kommt in der Applikation zum Einsatz, wenn eine zeitgesteuerte Verarbeitung benötig wird. Der Methodenaufruf kann wahlweise einmalig oder in einem bestimten Zeitintervall dauerhaft erfolgen. TLGen generiert ein Timer Service und seine Komponenten wie den Client des Timer Service, Timer Service und eine Callback-Klasse (siehe 3.8) für die Implementierung von eigener Fachlogik, die von diesem Service benötigt wird. Timer Services werden von TLGen in drei Varianten generiert: 1. Vollautomatisch, in diesem Fall werden die Start-, Stopp-Zeit - Aufrufe und die periodische Wiederholung automatisch nach der Timer Service - Initialisierung gesteuert. 2. Start - und Stopp - Zeit wird durch die Client-Aufrufe gesteuert. 3. Verwendet die automatische und manuelle Steuerungsmöglichkeit. Die Timer Services können z.B. von einer Session-Bean oder einer Message Driven-Bean verwendet werden. TLGen 75 StarData GmbH V 2.8 In Listing 59 ein Timer Service Beispiel. /** * This is a generate package for 'emails' * This is a timer service class */ @Stateless(name = EmailserviceBci.JNDI_NAME, mappedName = "vms/"+EmailserviceBci.JNDI_NAME+"/remote") @Remote(EmailserviceBci.class) public class EmailserviceSessionBean implements EmailserviceBci { private static final long serialVersionUID = 240781750; // Session annotations and fields for timer service @Resource private TimerService m_timerService; private static final String KOMMAND = "TLG"; @Inject private CallBackEmailserviceIf m_callBack; // Session class methods /** * Timer service method "initemails()" * @param start * @param stop * @param repeat * @return * @throws PersistenceException */ public void initemails(Date start, Date stop, long repeat) throws PersistenceException { try { // time to start and repeat timer service m_timerService.createTimer(start,repeat,KOMMAND); // time to stop timer service m_timerService.createTimer(stop,KOMMAND); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Timer service method "stopemails()" */ public void stopemails() { for(Object obj : m_timerService.getTimers()) { Timer timer = (Timer)obj; String command = (String)timer.getInfo(); if(command.equals(KOMMAND)) { timer.cancel(); } } } /** * Timer service method "timeoutemails()" * @param timer * @return */ @Timeout public void timeoutemails(Timer timer) { String command = (String)timer.getInfo(); if(command.equals(KOMMAND)) { m_callBack.checkEmails(this); } } } TLGen 76 StarData GmbH V 2.8 Listing 59: Beispiel eines „Timer Services“ In der Klassen-Methode „eu.stardata.server.CallBakcEmailService“ kann die gewünschte Fachlogik eingebaut werden (in der Methode checkEmails). 3.7.2 „Web Services“ Ein Web Service ist ein beliebiger Service (z. B. eine Session-Bean), der von einem Client über z.B. das Internet aufgerufen werden kann. Es werden zwei Arten von Web Services unterschieden, RPC (Remote Procedure Call) und DOCUMENT. RPC ist ein Aufruf einer Methode (z. B. eine Methode von einer Session-Bean) über Web. TLGen generiert für diese Services den Client, den Web Service und eine Callback-Klasse (siehe 3.8), falls diese nötig ist, um dort die nötige Fachlogik zu implementieren. In Listing 60 ein Beispiel einer Web Service-Klasse package eu.stardata.server.provider /** * A session bean encapsulates business logic that can be invoked programmatically * by a client over local, remote, or web service client views. */ @Stateless(name = ProviderBci.JNDI_NAME, mappedName = "vms/"+ProviderBci.JNDI_NAME+"/remote") @Remote(ProviderBci.class) @Web Service(endpointInterface = "eu.stardata.provider.client.bci.ProviderBci", serviceName = "ProviderSessionBeanService") public class ProviderSessionBean extends BaseSessionBean implements ProviderBci { // Session annotations and fields for local manager @Inject private CallBackServiceProviderIf m_callBack; ……………… public RetrieveServiceResponse retrieveServiceIn(RetrieveServiceRequest retrive) throws PersistenceException { try { return m_callBack.retrieveServiceIn(retrive); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } ……………. } Listing 60: „Web Service“-Klasse - Beispiel In der Klassen-Methode „eu.stardata.server.CallBakcPtroviderIf“ kann die gewünschte Fachlogik eingebaut werden (in der Methode retriveServiceIn). TLGen 77 StarData GmbH V 2.8 In Listing 61 das Interface dieser Web Service-Klasse. package eu.stardata.provider.client.bci @Remote @Web Service @SOAPBinding(style = SOAPBinding.Style.DOCUMENT) public interface ProviderBci { // Client interface Fields public final static String JNDI_NAME_PREFIX = "vms"; public final static String JNDI_NAME = "eu.stardata.server.provider.ProviderSessionBean"; public final static String MANAGER_NAME = "managerProvider"; public final static String EAR_NAME = "vms"; public final static String PACKAGE_NAME = "provider"; // Session - Client interface methods @WebMethod public RetrieveServiceResponse retrieveServiceIn(RetrieveServiceRequest retrive) throws PersistenceException; @WebMethod public UpdateServiceResponse updateServiceIn(UpdateServiceRequest update) throws PersistenceException; } Listing 61: „Web Service”-Interface 3.8 Callback-Klasse Die Callback-Klasse kann eine normale Java-Klasse oder eine Session Bean-Klasse sein. Der Aufruf einer Callback-Klasse von einer Session Bean ist in Listing 62 dargestellt. TLGen generiert den Aufruf dieser Klasse und eventuell seine Interfaces mit der Struktur von verwendeten Methoden. Die Programmierer werden diese Klassen mit dem selbsgeschriebenen FachCode, der Applikation versorgen. Die Kommunikation zwischen der aufgerufenen Klasse und der Callback-Klasse erfolgt über Methoden, die „Parameter“ und „Return“-Werte haben. @Inject private CallBackServiceUpsIf m_callBack; ……………………. public RetrieveServiceResponse retrieveServiceIn(RetrieveServiceRequest retrive) throws PersistenceException { try { return m_callBack.retrieveServiceIn(retrive); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } TLGen 78 StarData GmbH V 2.8 Callback Interface: @Local public interface CallBackServiceUpsIf { …………………………………… /** * retrieve the informations from the VMS system * @param adr * @return * @throws PersistenceException */ public abstract RetrieveServiceResponse retrieveServiceIn( RetrieveServiceRequest retrieve) throws PersistenceException; } Callback Class: public class CallBackServiceUps extends UpsFunctions implements Serializable, CallBackServiceUpsIf { …………………………….. @Override public RetrieveServiceResponse retrieveServiceIn(RetrieveServiceRequest retrieve) throws PersistenceException { …………..// Insert Fach Code } Listing 62: Callback-Klasse - Beispiel Diese Art von Klasse ist als Schnitstelle zwischen dem technischen Code, der von TLGen generiert wird, und dem fachlichen Code, der die Fachlogik der Applikation beinhaltet, gedacht. Die Generierung der Klasse kann wie folgt gesteuert werden: merge = 0, TLGen generiert diese Klasse immer wieder neu und überschreibt vorhandene. merge = 1, diese Klasse wird nur generiert, falls sie nicht existiert. merge = 2, Generierung einer neuen Klasse und Zusammenfassung dieser mit der Implementierung der vorhandenen 3.8.1 Free Klassen Diese „freien“ Klassen sind für den eigenen Programmteil des Projekts gedacht und beinhalten die Fachlogik. Diese muss selbst implementiert werden. Falls der Generator eine freie Klasse findet, welche angegeben wurde und sich innerhalb des Ordners „generated“ befindet, kann er, abhängig von einem Parameter „merge“, wie folgt diese überschreiben oder neu generieren: merge = 0, TLGen generiert diese Klasse immer wieder neu und überschreibt vorhandene. merge = 1, diese Klasse wird nur generiert, falls sie nicht existiert merge = 2, Generierung einer neuen Klasse und Zusammenfassung dieser mit der Implementierung der vorhandenen Merge = 3 generiert nur die neuen Methoden in eine schon existierende Klasse TLGen 79 StarData GmbH V 2.8 3.9 Generierung von Datenbank und SQL Skripte TLGen kann ein Datenbank SQL Skript aus einem Domainmodell mit seinen Tabellen, Spalten, Relationen, Indexes und Sequenzen generieren. Ist der Datenbankzugriff (User und Password) in der Konfigurationsdatei vorhanden, verwendet TLGen das generierte Skript, um die Datenbank zu generieren. Ein komplettes Beispiel einer SQL Script siehe in Kap: 7.3. UML-Parameter für die SQLSkript Generierung: 1. Regel für die SQL Tabellen Generierung: a. Die Kommentare werden aus den UML-Klassen übernommen und dem SQL Skript hinzugefügt. b. UML-Klassen als „persistent“ gekennzeichnet werden auch als Tabellen generiert, wobei für die „transienten“ Klassen nur die Daten-Klassen/Interfaces generiert werden. c. Constraints werden vom SQL Skript übernommen. Ist der Name „tablespace“ vorhanden, wird der Constrain String mit der aus der „Config“- XML -Datei Tablespace-Index Wert ergänzt. 2. Regel für die SQL Spalten/Columns: a. Die Spalten (UML-Klassenattribute), gekennzeichnet in der UML als „derived“, werden als „NOT NULL“-Felder generiert. b. Die Spalten, gekennzeichnet in der UML als „static“, werden als „UNIQUE“Felder generiert. c. Das Attribut „container“ im Collection UML Tail beim TAG „UML:TaggedValue“ muss die Länge dieser Variablen angeben, ansonsten werden die Standardwerte aus der Konfigurationsdatei übernommen (z.B. für String ist die Länge 255 Char). d. „Name“, „Type“ und „Initial“ werden von den dazugehörigen Tags übernommen. 3. Regel für Sequences: a. Weil einige Datenbanken wie z.B. Oracle eine begrenzte Länge für die Namen (30 char) haben, sind einige Regel für die Namengenerierung notwendig. Die zwei Regeln sind in TLGen implementiert : i. Sequence Type 0 (Dieser Wert ist eitragbar in der „Standard Konfiguration“ Datei, Tag <UmlControl>, Attribut „sequenceType“): Sequence-Name = „Table-Name“ + „Sequence Endung“ ii. Sequence Type 1: Sequence-Name = „Table-Name“ + „_“ + „ColumnName“ + „_ID“ + “Sequence Endung” TLGen 80 StarData GmbH V 2.8 Die “Sequence Endung” ist in der „Standard Konfiguration“ Datei, Tag <UmlControl>, im Attribut „endSequence“ einzutragen. Weil diese Kombination manchmal eine größere Namenlänge als der zugelassene Wert ergibt, wird diese mit Hilfe von Eintragungen in der „Standard Konfiguration“ -Datei verkürzt, Tag <UmlControl>, <NameChange>. Z.B.: <NameChange name="ProvisioningStatus_ProvisioningStatus_ID_1SQ" type="ProvisStat_ProvisStat_ID_1SQ"/> Der Name "ProvisioningStatus_ProvisioningStatus_ID_1SQ" wird mit dem Namen ProvisStat_ProvisStat_ID_1SQ. Ersetzt. Dies ist auch möglich, wenn die Datenbank schon vorhanden ist. Dann werden nur die Änderungen (es wird auch ein Änderungs-Skript generiert) generiert und somit werden die schon vorhandenen Daten nicht gelöscht. Skript-Beispiele in Listing 63: ----------- Drop all Tables ----------DROP TABLE Contract CASCADE CONSTRAINTS; DROP TABLE Product CASCADE CONSTRAINTS; ………………………………………………………… ----------- Create Tables ----------CREATE TABLE Product ( Product_ID NUMBER(19,0) NOT NULL, DB_VERSION NUMBER(16) NULL, description VARCHAR2(255) NULL, ……………………………………………………… shortName VARCHAR2(255) NULL, CustomerService_ID NUMBER(19,0) NULL, PRIMARY KEY (Product_ID) USING INDEX TABLESPACE XINDEX ) Tablespace XDATA; ……………………………………………………… ----- Foreign key -----ALTER TABLE Product ADD CONSTRAINT FK201A7DE FOREIGN KEY (CustomerService_ID) REFERENCES CustomerService; ALTER TABLE Contract ADD CONSTRAINT FKF96859 FOREIGN KEY (Customer_ID) REFERENCES Customer; ALTER TABLE Contract ADD CONSTRAINT FK31C7538 FOREIGN KEY (AccessControlContext_ID) REFERENCES AccessControlContext; ALTER TABLE Contract ADD CONSTRAINT FK7FE790 FOREIGN KEY (Offer_ID) REFERENCES Offer; …………………………………………………. ----------- Create Sequences ----------CREATE SEQUENCE Contract_SEQ START WITH 1 INCREMENT BY 1 CACHE 10 MINVALUE 1; CREATE SEQUENCE Product_SEQ START WITH 1 INCREMENT BY 1 CACHE 10 MINVALUE 1; Listing 63: SQL Skript Die sofortige Generierung einer Datenbank ist für den Datenbank Optimierungsprozess (neue und alte Projekte) wichtig (siehe Kap. 2.1). TLGen 81 StarData GmbH V 2.8 3.10 Regel für die Namengenerierung TLGen verwendet für die Namengenerierung im Code Generierungsprozess zwei Arten von Regeln: Die Domainmodell-Namen sind eigentlich Namen gemäß den Java Konventionen für Datenbank-Namen. In diesem Fall verwendet die Datenbanknamen-Generierung vorhandene Namen aus dem Domainmodell. Bei einer schon vorhandenen Datenbank (Legacy Projekte) gibt es in den meisten Fällen Namen, die anders als die Java Namenskonventionen sind. Für diesen Fall sind acht Namensumwandlungen möglich: o Aus den groß geschriebenen Namen, aus mehreren Teilen mit ein „underscore“ verbunden, wird ein Name kleingeschrieben, ohne „underscore“. (siehe Fehler! Verweisquelle konnte nicht gefunden werden., Zeile 1) o „underscore“ wird nicht mehr verwendet, d.h. der erste Buchstabe ist groß, Zeile 2 o „underscore“ wird nicht verwendet, der restliche Name bleibt gleich, Zeile 4 und 5 o „underscore“ wird verwendet, der restliche Name bleibt gleich, Zeile 6 o underscore“ wird verwendet und der restliche Name verwendet die Java NamenKonvention, Zeile 7 o keine Namen-Änderung. Tabelle 9: Namen-Regel Nr. Datenbank Format Java Format 1 CORE_FORMULAR Formular 2 CORE_FORMULAR CoreFormular testCoreFormular TestCoreFormular CORE_FORMULAR CoreFormular testCoreFormular TestCoreFormular FORMULAR Formular CORE_FORMULAR COREFORMULAR testCoreFormular TestCoreFormular CORE_FORMULAR CoreFormular testCoreFormular Testcoreformular 6 CORE_FORMULAR COREFORMULAR 7 CORE_FORMULAR Core_formular 8 CORE_FORMULAR CORE_FORMULAR 3 4 5 Details siehe auch in Kapitel 4.4. TLGen 82 StarData GmbH V 2.8 Diese Regeln können auch aus dem Domain-Modell in Bezug auf die Datenbank verwendet werden, jedoch machen die meisten Datenbanken keinen Unterschied zwischen Klein- und Grossschreibung. 3.11 Log Dateien - Beschreibung TLGen erzeugt im Generierungsprozess mehrere Log Dateien, die in allen Generierungsprozessen eingetragen werden. Durch diese Log Dateien kann kontrolliert werden, ob das ProjektDesign den gewünschten Ergebnissen entspricht. Die Verwendung von Log Dateien ist einstellbar und der Name ist wählbar, d. h. es kann bzw. können nur eine oder mehrere Log Dateien verwendet werden. Sind es mehrere, weil die Information in diesen Dateien sehr groß ist, wird die Verwendung dieser Dateien somit erleichtert. TLGen kann folgende Log Dateien verwenden: Eine Log Datei für die Generierung allgemeiner Schritte Eine Log Datei für die Generierung von Session Beans Eine Log Datei für die Generierung von Entity Beans Eine Log Datei für die Generierung von Test Klassen Eine Log Datei für die Generierung von Daten-Klassen/Interfaces Eine Log Datei für die Generierung von Manager-Klassen. Es gibt eine Error Log Datei, in der die Generierung Error, wie z. B. zu lange Namen, Fehler im Domainmodell (z. B. Kreise in Relationen) eingetragen werden. Ein Beispiel für eine Error Log Datei befindet sich in Listing 64 (siehe auch Kap. 2.1): Time Start : Sat Feb 05 13:29:11 CET 2011 0 Domain Error | Class-name is too lang[35] + 'AverageFlatDurationCalculationParam' ==== Direct circles in relations ============================================== Warning: TARGET [Order] in a path starting with himself as SOURCE [Order]: [Order(NOT NULL)>Customer(NULL)->Asset(NOT NULL)->AssetItem(NOT NULL)] ---> [Order] Warning: TARGET [Offer] in a path starting with himself as SOURCE [Offer]: [Offer(NOT NULL)>Customer(NULL)->Asset(NOT NULL)->AssetItem(NOT NULL)->Order(NOT NULL)->Contract(NOT NULL)] ---> [Offer] ……………………………………………….. ==== Relation Problems? ================================================== FATAL Error: [ServiceDescriptiontItem] needed by different mandatory relations starting from [AssetItemStatus] [AssetItemStatus->AssetItem->Order->Contract->ServiceDescription] ---> [ServiceDescriptiontItem] [AssetItemStatus->AssetItem->OrderItem] ---> [ServiceDescriptiontItem] FATAL Error: [ServiceDescription] needed by different mandatory relations starting from [AssetItem] [AssetItemStatus->AssetItem->Order->Contract] ---> [ServiceDescription] [AssetItemStatus->AssetItem->Order->Contract->Offer] ---> [ServiceDescription] Warning: [ProductRelation] can be reached over [AssetItem] in different relations: [AssetItemStatus->AssetItem->OrderItem->ServiceDescriptiontItem->Product] ---> [ProductRelation] [ServiceDescriptiontItem->AssetItem->OrderItem->Product] ---> [ProductRelation] [OrderItem->ServiceDescriptiontItem->AssetItem->Product] ---> [ProductRelation] TLGen 83 StarData GmbH V 2.8 Listing 64: Error Log Datei 3.12 Verwendung von Kommentarien bei generiertem Code TLGen generiert Kommentarien auf der Ebene von Klassen-Methoden. 3.12.1 Kommentarien für Klassen Für Klassen gibt es zwei Möglichkeiten Kommentarien im generierten Code zu verwenden. 1. Text-Kommentarien, die vom „package“ Eintrag dargestellt werden, die für alle Klassen gleich sind und vom „standard“ xml stammen wie in Listing 65. Wenn statt ein Kommentar Text im Attribut „commentary“ der String „false“ existiert, dann wird kein Kommentar generiert. 2. Innerhalb einer Klasse können verschiedene Kommentarien eingebaut werden; von jedem <Design> Tag und diese werden in allen Klassen, die zu diesem Tag (package) gehören, generiert (siehe Listing 66). In Klasse: /** * **** do not change with a file editor ***** */ package com.thgen.server.persistence.customer; und in “standard-config” xml Datei: und in “standard-config” xml Datei: <Standard name="Standard-VMS" …………………… commentary="**** do not change with a file editor *****" > Listing 65: Kommentarien für Klasse <Design name="common" > <Commentary name="This is a generate package for 'common'"/> Listing 66: Kommentar vom <Design> Tag In den UML Domain-Modell kann ein Kommentar im Attribut „note“ eingebaut werden. Dieser wird zusammen mit dem zuvor beschriebenen Kommentar vom <Design> Tag generiert, siehe Listing 67. Dieser Kommentar wird auch im generierten SQLSkript vor der dazugehörigen Tabelle eingebaut sowie in der „JSon“-Klasse, falls diese Klasse auch generiert wird. TLGen 84 StarData GmbH V 2.8 /** * This is a generate package for 'customer' * * A session bean encapsulates business logic that can be invoked programmatically * by a client over local, remote, or web service client views. */ …………………………… public class CustomerSessionBean implements CustomerBci Listing 67: Kommentar vom UMD Domain-Modell 3.12.2 Kommentarien für Methoden Kommentarien von Methoden kommen, wie im UML Domain Modell beschrieben, bei jedem Attribut vor und werden vor der „Get“ Methode, die diese Attribute darstellen, in alle SQL Skripts und Daten-Klassen generiert, siehe Listing 68. /** * last name of the customer */ public String getLastName() { return m_lastName; } public void setLastName(String arg) { m_lastName = arg; } Listing 68: Methoden Kommentar TLGen 85 StarData GmbH V 2.8 4 Verwendung von TLGen (Beschreibung der Konfigurationsdatei) 4.1 Was wird generiert Siehe Kapitel 1.2 4.2 Wie wird Code generiert? TLGen generiert den Java Code mit Hilfe eines Domain Modells (UML) für neue Projekte, einer existierenden Datenbank für Legacy Projekte und zwei Konfigurationsdateien. Spezifisch für TLGen sind nur die Konfigurationsdateien im XML Format, eine Default-Konfigurationsdatei und die projektspezifischen Konfigurationsdateien. Der Aufwand zur Erstellung der projektspezifischen Konfigurationsdatei ist sehr gering, da üblicherweise nur ein paar Parameter, abhängig vom eigenen Projekt, angepasst werden muss. Die restlichen Parameter werden automatisch von den Default-Werten übernommen (siehe Kap 4.3 und 4.4). Diese Default-Werte können durch die Default Konfigurationsdatei überschrieben, im Generierungsprozess verwendet werden und gelten dann für alle projektspezifischen Konfiguraionsdateien. Default-Werte können in der projektspezifischen Konfigurationsdatei überschrieben werden. Diese Informationen-Verkettung für den Generierungsprozess ist für Firmen gedacht, welche viele Projekte haben und bestimmte Standard-Werte für alle Projekte benötigen, z.B. Layout des generierten Codes. Die Unterschiede zwischen Projekte (fachprojektspezifisch) werden mit Hilfe der projektspezifischen Konfigurationsdatei geregelt. So kann die Default Konfigurationsdatei nur allgemeine Informationen beinhalten, welche alle untergeordneten Projekte dann verwenden. Für Firmen, die wenige Projekte entwickeln, ist die detaillierte Steuerung von ProjektHierarchien (mit der Default-Konfigurationsdatei und mehreren Projekt-Konfigurationsdateien) für die Code- Generierung uninteressant und kann deshalb entfallen. 4.3 Ordnerstruktur für den generierten Code Eine übersichtliche und fachgerechte Strukturierung von Ordnern für den neu generierten Code vereinfacht die Wartung und Weiterentwicklung von neuen oder refaktorieten Projekten. Für den neu generierten Code schlagen wir folgende Ordner-Struktur vor (siehe Abbildung 16). TLGen 86 StarData GmbH V 2.8 Für den generierten Code gibt es für die Pfad-Struktur „de.stardata.demo“ (mit dem Projektnamen „demo“) folgende drei Unterordner: bussines Ordner, in welchem die Daten-Objekte generiert werden client, der Code für die Client-Aufrufe: o bci (business common interface), Ordner, wo die Verbindungszugriffe zwischen Client und Server generiert werden o message Ordner, wo die Client Message-Klassen generiert werden sollten o test Ordner, wo die JUnit-Test-Klassen generiert werden server Ordner, wo Server-Klassen generiert werden o message Ordner für die Message Beans o persistence Ordner, wo sich alle Klassen, notwendig für die Daten-Persistence, befinden, wie die Session Beans, Entity Manager, Entities Beans, etc. Abbildung 16: Ordner-Struktur TLGen 87 StarData GmbH V 2.8 Diese Ordner-Struktur ist nur eine Empfehlung seitens TLGen Generator Team, denn eigentlich kann jeder die eigene Struktur über die Konfigurationsdatei definieren. 4.4 Default Konfigurationsdatei Wie zuvor schon beschrieben, beinhaltet diese Konfigurationsdatei die allgemeinen Informationen, die in mehreren Projekten verwendet werden können. In den folgenden Kapiteln werden die Parameter und Einstellungen genauer beschrieben. Für die Code-Generierung mit Hilfe von TLGen aus einem Domain-Modell (UML) oder aus einer vorhandenen Datenbank (z.B. für Legacy-Projekte) heraus gibt es nur einen Unterschied, nämlich das Setzen eines Parameters. 4.4.1 Default Konfigurationsdatei - Struktur Die Default Konfigurationsdatei hat folgende XML-Struktur (siehe Listing 69): <?xml version="1.0" encoding="UTF-8"?> <Standard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="C:\Project-TLGen-2.2\config\template\DefaultSchema.xsd"> <Project/> <Locator></Locator> <Class> <Extends/> </Class> <Entity> <Implements/> <Extends/> <Annotation/> </Entity> <Mapping> </Mapping> <Criteria> </Criteria> <JSon> </JSon> <Manager> <Extends/> <Implements/> <Annotation/> <Method> <Exception/> <Parameter/> </Method> </Manager> <Session> <Extends/> <Annotation/> <Client> <Extends/> <Annotation/> <Variable/> </Client> TLGen 88 StarData GmbH V 2.8 <Xml-persistence> <Property/> </Xml-persistence> <Interceptor> <Method> <Annotation/> <Parameter/> <Exception/> </Method> </Interceptor> <Freeclass> </Freeclass> </Session> <Message> </Message> <UmlControl> <Column/> <ColType/> <NameChange/> <Relation/> <Association/> <RelationType/> <AggregationType/> <DirectionType/> <AssociationType/> <AssociationSubType/> <Navigability/> <Compare/> </UmlControl> </Standard> Listing 69: Default Konfigurationsdatei Die Default Konfigurationsdatei verwendet folgende Tags: Standard Tag, ist der Main Tag. Locator Class Entity Mapping Criteria JSon Manager Session o Client o Xml-persistence o Interceptor o Freeclass Message UmlControl TLGen 89 StarData GmbH V 2.8 Die detaillierte Beschreibung dieser Tags und deren Attribute sind im folgenden Kapitel dargestellt. 4.4.2 Default Konfigurationsdatei - Beschreibung Die Default Konfigurationsdatei beinhaltet allgemeine Einstellungen und Parameter und ist für eine Gruppe von Projekten gedacht, welche in der Projekt Konfigurationsdatei überschrieben werden können. Bemerkung: Strings in den Attributen innerhalb eines Tags welche mit einem „%“ beginnen und enden (z.B. %package%) sind Ersetzungsnamen oder Platzhalter, welche der Generator dann automatisch einsetzt (z.B. alle Entities mit Ihren richtigen packages). Des Weiteren sind alle Werte eines Tag-Attributs, wie name=„com.tlgen.common.bci.ServiceLocator“ (hier eine Klasse), nur Beispiele, sie müssen aber nicht verwendet werden. TLGen wurde mit diesen getestet und diese entsprechen auch den Standard-Aufrufen. 4.4.2.1 <Standard> Tag Ist der Main Tag für diese XML. Es gibt folgende Attribute: name: Projekt-Name company: Firmen-Name path: Allgemeine Pathstruktur, z.B. „eu.stardata.%project%“ Commentary: Kurzbeschreibung des Projekts 4.4.2.2 <Project> Tag Siehe Kapitel 4.5.2.2. 4.4.2.3 <Locator> Tag Es ist ein optionaler Tag. Dieser Tag beinhaltet die Klasse für die RMI-Verbindung. Gibt es keine Eintragungen in diesem Tag, wird die Default-Klasse verwendet. Folgende Attribute werden mit den Default-Werten verwendet: name = „com.tlgen.common.bci.ServiceLocator“, Standard Locator-Klasse instance = “getInstance”ist der Methoden-Name für die Instanz local = „getLocalReference“ Methoden-Name des lokalen RMI-Aufrufs TLGen 90 StarData GmbH V 2.8 remote = "getRemoteReference" Methoden-Name des Remote-Aufrufs 4.4.2.4 <Class> Tag Dieser ist ein optionaler Tag und kann auch über die projektspezifische Konfigurationsdatei über die <Class>-Tags überschrieben werden. Der Tag generiert Daten-Klassen und Ihre Interfaces. Dazu gehören folgende Attribute: path = „de.stardata.demo.business“, Klassen/Interface-Pfad und optionales Attribut name = "de.stardata.demo.business.%package%.data.%classname%Data| de.stardata.demo.business.%package%.dataif.%classname%DataIf", der Name beinhaltet zwei Teile, für die Klassen bzw.Interfaces, getrennt durch “|“. Die Attribute der zwei Platzhalter sind: o %package% ist der Package-Name. Dieser wird vom Generator mit dem Package-Namen aus dem Domain-Modell ersetzt oder aber aus den festgelegten Namen aus der projektspezifischen Konfigurationsdatei. o %classname% dieses Attribut wird automatisch vom Generator mit dem ObjektNamen aus dem Domain-Modell ersetzt oder mit den Werten der TabellenNamen (werden eventuell durch die Rules geändert) aus der Datenbank. pathEnum = "de.stardata.demo.business.%package%.%classname%" wird für die Generierung von Enums verwendet. Die Platzhalter haben die gleiche Bedeutung wie zuvor erwähnt. pathType = “de.stardata.demo.business.%package%.%classname%” wird für die Typen Klassen verwendet. Dieser Tag hat zwei Kind-Tags, die optional sind und folgende Standard-Einstellung haben: <Extends name="com.tlgen.common.data.BaseData"/> kann eigene Super-Klassen verwenden. <Extends name="com.tlgen.common.data.BaseDataIf" type="interface"/> 4.4.2.5 <Entity> Tag Dieser Tag versorgt den Generator mit Informationen über die Entities. Es ist ein optionaler Tag. Fehlt dieser, werden die Default-Informationen (z.B. mit Hilfe des Domain Modells) verwendet oder können über die projektspezifische Konfigurationsdatei überschrieben werden. Entity Tag hat folgende Attribute: path = "de.stardata.server.persistence" (Beschreibung wie unter 4.4.2.5) name = "de.stardata.server.persistence.%package%.entity.%classname%Entity" (Beschreibung wie unter 4.4.2.5) seqstrategy="SEQUENCE" ist der Default-Wert. Dieses Attribut ist für die automatische Generierung von einem Primary Key notwendig (z.B. für die Datenbank Oracle). TLGen 91 StarData GmbH V 2.8 Dieser Tag hat folgende Kinder-Tags, die optional sind: <Implements> mit Attribut Name="java.io.Serializable" <Extends> mit Attribut Name="com.tlgen.common.ejb.entity.BaseEntityBean", z.B. eine Standard Super-Klasse wie <Extends name="com.tlgen.common.ejb.entity.BaseEntityBean"/> <Annotation>, dieser Tag ist optional und der Generator kann damit folgende Annotationen in die Entities generieren: o "javax.persistence.Entity" o "javax.persistence.Table" der Generator übernimmt automatisch den TabellenNamen o "javax.persistence.SequenceGenerator" 4.4.2.6 <Mapping> Tag Dieser Tag versorgt den Generator mit Informationen über die Mapping-Klassen zwischen Data-Klassen und JSon-Klassen. Es ist ein optionaler Tag. Fehlt dieser, werden die DefaultInformationen verwendet. <Mapping> Tag hat folgende Attribute: name = „eu.stardata.%project%.business.%package%.%classname%Map“ 4.4.2.7 <Criteria> Tag Dieser Tag versorgt den Generator mit Informationen über die Criteria-Klassen. Es ist ein optionaler Tag. Fehlt dieser, werden die Default-Informationen verwendet. <Criteria> Tag hat folgende Attribute: name = „eu.stardata.%project%.business.%package%.%classname%Criteria“ 4.4.2.8 <JSon> Tag Dieser Tag versorgt den Generator mit Informationen über die JSon Daten-Klassen. Es ist ein optionaler Tag. Fehlt dieser, werden die Default-Informationen verwendet. <Criteria> Tag hat folgende Attribute: TLGen 92 StarData GmbH V 2.8 name = „eu.stardata.%project%.business.%package%.%classname%JSon“ 4.4.2.9 <Manager> Tag Dieser Tag versorgt den TLGen Generator für die Generierung mit Informationen von Entity Manager und hat folgende Attribute: name="eu.stardata.server.persistence.%package%.manager.%classname%Manager (Beschreibung wie unter 4.4.2.9) transactiontype: z.B."JTA“ ist ein Standard Wert. Exception: Zur Verwendung einer eigenen Exception-Klasse, z.B. "com.tlgen.common.exception.PersistenceException". Dieser Tag hat folgende Unter-Tags, die optional sind: <Extends> mit Attribut Name=" com.tlgen.common.ejb.manager.BaseManager " <Annotation>, dieser Tag ist optional und folgende Annotationen sind z. B. für die Entities möglich: o "javax.ejb.Stateless" o "javax.ejb.Local" 4.4.2.9.1 Fields für Entity Manager Für den Manager werden folgende notwendige Fields automatisch generiert (für den Tag <Variable> siehe auch 4.4.2.9.1): 1. name="JNDI_NAME" vartype="string" content="%interfacemanager%" fieldtype="1" abstract="true" 2. name="EAR_NAME" varitype = "string" content="%earname%" fieldtype="1" abstract="true" 3. name="m_manager" vartype = "javax.persistence.EntityManager" type="%clientdata%.MANAGER_NAME". Für dieses Field werden folgende Annotation generiert: a. name="javax.persistence.PersistenceContext"mit folgenden Parametern: i. name="properties" type="Text-Prop"/> ii. name="unitName" type="%clientdata%.MANAGER_NAME" 4.4.2.9.2 Methoden für Entity Manager TLGen 93 StarData GmbH V 2.8 Für den Tag <Method> siehe auch 4.4.2.10. Die Manager Bean-Methoden können in drei Kategorien eingeteilt werden: Es sind Methoden, die intern vom Manager Bean gebraucht werden, Methoden, die vom Client über die Session-Beans aufgerufen werden und für die Verwaltung des Persistenz-Prozesses notwendig sind und als dritte Kategorie sind die Methoden für die Persistenz-Verwaltung, welche vom User über die Konfigurationsdatei übergeben werden (siehe 4.5.2.4.3.1). Die Methoden im Manager können auch eine Exception werfen und werden mittels Tags <Exception> individuell gesteuert. Dieser Tag hat ein Attribut „name“ und braucht den kompletten Namen der Exception-Klasse. Folgende interne Methoden werden für den Manager Bean standardmäßig generiert: 1. name="getManager" return="%interfacemanager%" methodtype="4", holt vom BeanContainer den aktuellen Manager. 2. name="getEntityByPrimaryKey" return="%Klassentity%" methodtype="5" Folgende Methoden werden standardmäßig für die Remote-Verwendung generiert: 1. name="create" return="%interfacedata%" methodtype="4", speichert ein neues Objekt in der Datenbank ab. Der Platzhalter %interfacedata% wird vom Generator automatisch mit dem richtigen Interface Namen ersetzt. 2. name="update" methodtype="4", ändert ein Datenobjekt in der Datenbank 3. name="remove" methodtype="4", löscht ein Objekt in der Datenbank 4. name="flush" methodtype="4" 5. name="close" methodtype="4" 6. name="clear" methodtype="4" 7. name="findByPrimaryKey" return="%interfacedata%" methodtype="5", sucht ein Objekt in der Datenbank nach dessen PrimaryKey. Der Platzhalter %interfacedata% wird vom Generator mit dem Interface Name ersetzt. 8. name="findAll" return="%interfacedata%[]" methodtype="5", holt alle Objekte für diesen Manager-Bean aus der Datenbank. Der Platzhalter %interfacedata% wird vom Generator mit dem Interface Name ersetzt. 4.4.2.10 <Session> Tag Dieser Tag versorgt den Generator mit allgemeinen Informationen für die Generierung der Session Beans. Falls dieser nicht vorhanden ist, werden die Default-Daten für die Generierung verwendet. Der Session Bean Tag hat folgende Attribute: TLGen name="de.stardata.demo.server.persistence.%package%.%classname%SessionBean", ist der Name (%classname%) und dazu der Pfad - Platzhalter (%package%) für alle Session Beans. 94 StarData GmbH V 2.8 managername="manager%classname%", gibt dem Manager Informationen, die für die „persistence.xml“ Datei notwendig sind (siehe 0) transactiontype, Transaktions-Typ (z.B. JTA). Session Bean hat z.B. folgende mögliche Annotationen: name="javax.ejb.Stateless"oder „javax.ejb.Stateful“ name="javax.ejb.Remote" Werden Session Beans als Web Services oder Timer Services generiert, können auch andere Annotationen verwendet werden (siehe 4.5.2.4.6.4, 4.5.2.4.6.5) 4.4.2.10.1 Methoden in Session Bean Eine Session Bean übernimmt alle oder nur die auserwählten Methoden vom Entity Manager, aufgerufen über die jeweilige Session Bean (Details siehe 4.5.2.4.6.1). Die Namen der Methoden werden aus dem Namen der Methode und dem Manager-Namen zusammengesetzt, da z.B. der Aufruf „findByPrimaryKey“ für jedes Entity nützlich ist und von mehreren Managern benötigt wird. Z.B. das Manager Formular hat im Session-Bean den zusammengesetzten Aufrufnamen aus „findByPrimaryKey“ und seinem Namen: „findByPrimaryKeyFormular“. Diese Namen werden bis zum Client gleichbleibend verwendet, d.h. auch in den Client Interfaces/Daten-Klassen (DAOs). 4.4.2.10.2 <Client> Tag Ist ein Tag innerhalb der Session Beans und dient zur Generierung von Client-Aufrufen. Auch dieser Tag ist optional und wird er nicht verwendet, generiert der Generator Standard-Aufrufe. Dieser Tag hat folgende Attribute: name="de.stardata.demo.client.bci.%package%.%classname%Bci" exception = "com.tlgen.common.exception.PersistenceException" TLGen 95 StarData GmbH V 2.8 4.4.2.10.3 <Xml-persistence> Tag Der Tag setzt die Properties der persistence.xml, die z.B. in einer EAR benötigt werden, um die eigene Applikation in einem Application Server zu installieren. Diese Werte sind Applikation Server abhängig. Statt das Attribut value wird hier type für <Property> verwendet. Beispiel: JBoss 5.x brauchte bei Verwendung der Oracle-Datenbank 11x die folgende Information, um eine Verbindung zur Datenbank aufzubauen: <Property name="hibernate.dialect" type="org.hibernate.dialect.Oracle10gDialect" /> 4.4.2.10.4 <Interceptor> Tag EJB3 bietet die Möglichkeit an, eigene Interceptors zu verwenden. Folgende Attribute können für diesen Tag verwendet werden: name="de.stardata.demo.server.persistence.%package%.TimeCore", kompletter Klassen-Name des Interceptors (Pfad) path ="C:/Project-TLGen-2.2/source/generated", ist der Pfad, wo die Klasse generiert wird. Ist dieser nicht vorhanden, wird der Interceptor in denselben Pfad wie der Session Bean hinein generiert. Ein Interceptor kann mehrere Methoden mit folgenden Daten haben: name="timeTrace", interceptor name return="java.lang.Object" , Rückgabewert finally="C:/Project-TLGen-2.2/resources/FinallyTime.xml" 4.4.2.11 <Message Driven> Tag Dieser wird für Message Driven Beans verwendet und hat folgendes Attribut: name="de.stardata.demo.server.persistence.%package%.message" 4.4.2.12 <UmlControl> Tag Dieser Tag wird für die Generierung der Klassen aus den UML Domain Datenmodellen benötigt. Da dies feste Einstellungen sind und z.B. die Standard UML-Relationen der Klassen festlegen, sollten diese Werte nicht geändert werden. Folgende Attribute sind für diesen Tag verwendbar: TLGen 96 StarData GmbH V 2.8 name ist der Domen Modell Name z.B. "Demo-DM" lenString ist die Default Strings Länge wenn keine im Domain Modell definiert ist z.B. „255“ versionDb ist der Name für die Version Variable in Entity Bean, z.B. „OPTLOCK“ versionDbType ist die Variable Version Type in DB, z.b. „NUMBER(12,0)“ enumType ist die Type von „enum“ in DB, z.B. "VARCHAR2(32)" primKeyType ist den Primary Key Type in DB, z.B. "long" endSequence ist die Endung vom Sequence Namen in DB, z.B. "_1SQ" sequenceType ist die Sequence Type, z.B. “1” sequenceCache ist die Sequence Cache Größe, z.B. „10“ sequenceInit ist der Inititalisierungswert für die DB Sequence, z.B. „1“ sequenceIncrement ist der Increment für den Sequence Wert, z.B. „1“ dataTablespace ist der Name vom Tablespace für Daten in DB, z.B. "ADMDATA" indexTablespace ist der Name vom Tablespace für Index in DB, z.B. "ADMINDEX" Folgende Tags können im Tag <UmlControl> verwendet werden: <Column> legt die Daten für ein bestimmtes column in der Datenbank fest. Diese Column wird bei der Generierung von SQL Skript in allen Tabellen eingebaut, z.B. siehe Listing 70 <Column name="EJB3_OPTLOCK" type="long" dbType="NUMBER" dataLen="16" locking="true"/> <Column name="MODIFY_DATE" type="Date" dbType="TIMESTAMP" dataLen="0" locking="false" nullable="true" defaultValue="CURRENT_TIMESTAMP"/> Listing 70: <Column> Tag <ColType> legt die Datenbank Typen für ein Column fest. Es gibt Default Werte (siehe Listing 71 und Listing 72) für diesen Tag, können aber geändert werden <ColType name="char" type="CHAR"/> <ColType name="Date" type="TIMESTAMP(6)"/> <ColType name="String" type="VARCHAR2"/> <ColType name="DbType" type="NUMBER(10,0)"/> <ColType name="byte[]" type="BLOB"/> <ColType name="int" type="NUMBER(12,0)"/> <ColType name="Integer" type="NUMBER(12,0)"/> <ColType name="long" type="NUMBER(24,0)"/> <ColType name="Long" type="NUMBER(24,0)"/> <ColType name="double" type="NUMBER(28,4)"/> <ColType name="Double" type="NUMBER(28,4)"/> <ColType name="float" type="NUMBER(12,2)"/> <ColType name="Float" type="NUMBER(12,2)"/> <ColType name="short" type="SMALLINT"/> <ColType name="Short" type="SMALLINT"/> <ColType name="boolean" type="NUMBER(1,0)"/> <ColType name="Boolean" type="NUMBER(1,0)"/> Listing 71: Default Values für <ColType> Tag, z.B. für Oracle <ColType name="char" type="CHAR"/> <ColType name="Date" type="TIMESTAMP"/> TLGen 97 StarData GmbH V 2.8 <ColType name="String" type="VARCHAR"/> <ColType name="TIMESTAMP" type="TIMESTAMP"/> <ColType name="DbType" type="int"/> <ColType name="byte[]" type="BLOB"/> <ColType name="Text" type="Text"/> <ColType name="int" type="int"/> <ColType name="Integer" type="int"/> <ColType name="long" type="bigint"/> <ColType name="Long" type="bigint"/> <ColType name="double" type="double"/> <ColType name="Double" type="double"/> <ColType name="float" type="float"/> <ColType name="Float" type="float"/> <ColType name="short" type="SMALLINT"/> <ColType name="Short" type="SMALLINT"/> <ColType name="byte" type="TINYINT"/> <ColType name="dec" type="DEC"/> <ColType name="boolean" type="boolean"/> <ColType name="TablespaceExtra" type="ENGINE=InnoDB DEFAULT CHARSET=utf8"/> Listing 72: Default Values für <ColType> Tag, z.B. für MySQL <NameChange> ändert den Namen eines Domain Modell Objekts in der Datenbank, siehe Listing 73 <NameChange name="User" type="UserTable"/> Listing 73: <NameChange> Tag <Relation> Der Relation Tag ändert den Algorithmus, um z.B. rekursive Richtungen zu erlauben und einen anderen Namenszusatz zu den Methoden-Namen zu addieren, damit es keine Codekonflikte gibt. Rekursive Relationen: o o type="recursiv" name="recursiv" mit value=“true“ erlaubt rekursive Relationen (false für nicht). type="recursiv" name="recursivName" mit value="Parent" addiert zum Relation Methoden-Namen rekursiver Relationen “Parent” Mehrere Relationen in einer Klasse: o o type="sameRelationDirection" name="sameRelationDirection" erlaubt mehrere Relationen in einer Klasse (false für nicht). type="sameRelationDirection" name="sameRelationDirectionName" addiert zum Relation Methoden-Namen weiterer Relationen “Parent” Mehrere Rück-Relationen in einer Klasse: o o TLGen type=" backRelationDirection" name=" backRelationDirection" erlaubt mehrere Relationen in einer Klasse (false für nicht). type=" backRelationDirection" name=" backRelationDirectionName" addiert zum Relation Methoden-Namen weitere Relationen “Parent” 98 StarData GmbH V 2.8 <Association> Assoziation behandeln die OneToOne-, OneToMany-, ManyToOne- und ManyToManyRelationen. Um den ENUM-Typ der Assoziation „Shared“ und „Composition“ und deren Möglichkeiten (z.B. cascade) der Richtungen zu bestimmen (siehe Kapitel 2.1.1.3.1). Beispiel: <Association type="Composition" name="Composition:Source -> Destination|toSource" position="Source" navigable="Source" optional="false" nullable ="false" /> Um den ENUM-Typ OneToOne-, OneToMany-, ManyToOne- oder ManyToMany fest zu überschreiben, können diese festgelegt werden (siehe Kapitel 2.1.1.3.2). Das Attribut overwrite muss auf „true“ gesetzt werden. Beispiel: <Association type="OneToMany" name="OneToMany" overwrite="true" direction="true" insertable="true" updateable="true" /> <RelationType> Relationstyp setzt vorhandene ENUMs, welche auf die UML-Multiplizität Strings in der XMI Mappen. z.B. „m0_infinite“ auf „*“ oder auch auf „0..*“. Enums: mStandard, mNull, m0, m1, m0_1, m0_n, m0_infinite, m0_infinite, m1_n, m1_infinite, mm_n. Beispiel: <RelationType name="m0_infinite" type="RELATION_TYPE" return="Many" value="*"/> <AggregationType> AggregationType setzt die vorhandenen ENUMs (None, Shared, Composition), welche auf die UML-Assoziationarten Strings in der XMI mappen. Z.B. „None“ auf „none“. Beispiel: <AggregationType name="None" type="UML_ASSSOCIATION_TYPE" return="association" value="none"/> <DirectionType> DirectionType setzt die vorhandenen ENUMs (Unspecified, SourceToDest, DestToSource, BiDirectional), welche auf die Richtungs-Strings in der XMI mappen. Z.B. „BiDirectional“ auf „Bi-Directional“. Beispiel: <DirectionType name="BiDirectional" type="UML_CONNECTION_END_TYPE" return="bidirectional" value="BiDirectional"/> TLGen 99 StarData GmbH V 2.8 <AssociationType> AssotiationType setzt die vorhandenen ENUMs (Association, Aggregation), welche auf die UML-Assoziationarten Strings in der XMI mappen. Z.B. „Aggregation“ auf „Aggregation“. Beispiel: <AssociationType name="Aggregation" type="UML_ASSSOCIATION_TYPE" return="aggregation" value="Aggregation"/> <AssociationSubType> AssociationSubType setzt die vorhandenen ENUMs (Association, Strong, Weak), welche auf die Assoziationsubarten Strings in der XMI mappen. Z.B. „Association“ auf „Association“. Beispiel: <AssociationSubType name="Association" type="UML_ASSSOCIATION_TYPE" return="association" value="null"/> <Navigability> Navigability setzt die vorhandenen ENUMs (None, Navigable, NonNavigable, Unspecified), welche auf die Navigation Strings in der XMI mappen. Z.B. „None“ auf „None“. Beispiel: <Navigability name="Navigable" type="UML_CONNECTION_END_NAVIGABLE_TYPE" return="navigable" value="Navigable"/> <Compare> Compare setzt die vorhandenen ENUMs (manytomany, onetomany, manytoone, onetoone), ob sie eine einfache Relation oder auch eine “many”-Relation sind. Beispiel: <Compare name="manytoone" type="RELATION_TYPE" return="ManyToOne" value="Many" /> <Compare name="manytoone" type="RELATION_TYPE" return="ManyToOne" value="One"/> 4.4.2.13 <Method> tag Siehe Kap. 4.5.2.5 4.4.2.14 <Variable> Tag Siehe Kap. 4.5.2.6 4.5 Projekt Konfigurationsdatei TLGen 100 StarData Gmb V 2.8 Die Projekt Konfigurationsdatei gibt dem TLGen-Generator projektspezifische Daten über das Projekt. Die Daten aus der Konfigurationsdatei überschreiben die vorhergehenden Daten, die Default-Werte sowie die aus der Standard-Konfigurationsdatei. 4.5.1 Projekt Konfigurationsdatei - Struktur Die Default Konfigurationsdatei hat folgende XML Struktur (siehe Listing 74): <?xml version="1.0" encoding="UTF-8"?> <Generator xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="C:\Project-TLGen-2.2\config\template\ConfigSchema.xsd"> <Project> <Design> <Commentary/> <Class> <Extends/> </Class> <Entity> </Entity> <Manager> <Extends/> <Implements/> <Method> <Exception/> <Parameter/> <Sql/> </Method> </Manager> <Session> <Extends/> <Annotation/> <Client> <Extends/> <Annotation/> <Variable/> </Client> <Timerservice> <Extends/> <Annotation/> <Variable/> <Method/> </Timerservice> <Xml-persistence> <Property/> </Xml-persistence> <Method> <Exception/> <Parameter/> </Method> </Session> <Messagedriven> <Extends/> <Annotation/> <Client/> <Bean> <Callback/> </Bean> </Messagedriven> <Test> <Extends/> <Import/> TLGen 101 StarData Gmb V 2.8 <Method> <Exception/> <Parameter/> </Method> </Test> <Dbtable> <Relation> <JoinColumn/> <JoinTable> <JoinColumn/> <InverseJoinColumn/> </JoinTable> </Relation> </Dbtable> </Design> </Project> </Generator> Listing 74: Konfigurationsdatei 4.5.2 Projekt Konfigurationsdatei - Beschreibung Die Konfigurationsdatei erlaubt detaillierte Einstellungsmöglichkeiten und kann alle vorherigen Daten überschreiben. 4.5.2.1 <Generator> Tag Dieser ist das Hauptelement und versorgt den Generator mit allgemeinen Informationen über die Code Generierung. Folgende Attribute können verwendet werden (siehe Table 10). Die verwendeten Attribute können nach der Generierung in der „log“ Folder ersichtlich sein. Table 10: Attribute für den Generator Tag Nr. Attribute Name Pflichfeld Beispiel-Wert Kommentar 1 name no Demo Projekt Name 2 inputsource yes database 3 location yes C:/Projects/Project-RMA/project Die Addresse sollte vom Code generiert werden 4 datasource yes java:/efpPool Conditioned from App.Server TLGen 102 StarData Gmb V 2.8 5 appserver yes JBoss 6 standardConfigFile yes C:/Project-TLGen2.5/config/config_tlgen_demo_d efault.xml 7 umlFile yes/no C:\Project-TLGen2.5\doc\model\DomainModelDemo-01.xml Is mandatory only for type=guml and is the XMI file from the UML domain model 8 databaseConnect yes jdbc:oracle:thin:@localhost:1521 :orcl Connect string to the database 9 database yes ORACLE Database name 10 userPwd yes demo/demo For access to the database 101 type yes guml/gdb guml - generated from a domain model - gdb generated from a database. 12 mapping no true 13 rule no 3 Default is 0, siehe 4.5.2.1.1 14 databaseScript yes/no C:/Project-TLGen2.5/doc/db/demo_schema.sql Is mandatory for makeDatabse=true and type=guml 15 makeDatabase no true Generate a new Database with the help of a generated SQL-script 16 makeDatabaseDiff 17 indexTablespace yes/no DEMOINDEX Mandatory only if generating a database 18 dataTablespace Yes/no DEMODATA Mandatory only if generating a database 19 makeJavaCode no true 20 initProgram no 21 keyName no 22 reference no Generate a different SQL-script true 4.5.2.1.1 Regel für Namen-Transformation in Klassen, Methoden und Tabellen Mit TLGen kann folgende Regel für die Namen-Generierung verwenden: TLGen RULE_DEFAULT_VALUE = 0, Default value, no underscore, if all is upper, then first char is upper, rest is lower amd the rest is not changed. Examples: o ‘CORE_FORMULAR_PAGE_FIELD’ -> ‘CoreFormularPageField’ o ‘bruttoNettoSpecification’ -> ‘BruttoNettoSpecification’ o ‘_FIELDLONGDATA_’ -> ‘Fieldlongdata’ 103 StarData Gmb V 2.8 RULE_NO_UNDERSCORE = 1, No underscore. Examples: o ‘CORE_FORMULAR_PAGE_FIELD’ -> 'COREFORMULARPAGEFIELD’ o 'bruttoNettoSpecification' -> 'bruttoNettoSpecification’ o '_FIELDLONGDATA_ -> 'FIELDLONGDATA’ RULE_NO_UNDERSCORE_FIRST_UPPER = 2, No underscore, first char is upper, the rest is not changed. Examples: o 'CORE_FORMULAR_PAGE_FIELD' -> 'COREFORMULARPAGEFIELD' o 'bruttoNettoSpecification' -> 'BruttoNettoSpecification' o '_FIELDLONGDATA_' -> 'FIELDLONGDATA' RULE_DEFAULT_WITHOUT_FIRST = 3, Default, without the first tail before the first underscore (for legacy programs). Examples : o 'CORE_FORMULAR_PAGE_FIELD' -> 'FormularPageField' o 'bruttoNettoSpecification' -> 'BruttoNettoSpecification' o '_FIELDLONGDATA_' -> 'Fieldlongdata' RULE_NO_UNDERSCORE_FIRST_UPPER_REST_LOWER = 4, No underscore, first char is upper, rest is lower. Examples : o 'CORE_FORMULAR_PAGE_FIELD' -> 'CoreFormularPageField' o 'bruttoNettoSpecification' -> 'Bruttonettospecification' o '_FIELDLONGDATA_' -> 'Fieldlongdata' RULE_NO_UNDERSCORE_FIRST_UPPER_ALL_REST_LOWER = 5, No underscore, first char is upper, all rest is lower. Examples: o 'CORE_FORMULAR_PAGE_FIELD' -> 'Coreformularpagefield' o 'bruttoNettoSpecification' -> 'Bruttonettospecification' o '_FIELDLONGDATA_' -> 'Fieldlongdata’ RULE_NO_CHANGE = 6, No change 4.5.2.2 <Project> Tag Dieses Element versorgt den Generator mit den projektspezifischen Daten. Die Attribute für diesen Tag sind in der Tabelle 11 aufgeführt. Die verwendeten <Project> Attribute können nach der Generierung in die „log“ Dateien ersichtlich sein. Anmerkung: Sind die „no“-Pflichfelder nicht in der Konfigurationsdatei vorhanden, werden die Standardwerte verwendet. Tabelle 11: Attribute für den Projekt-Tag Nr. Attribute Name Pflicht feld Default/Beispiel-Wert Kommentar 1 name no Project StarData Demo Project Name 2 initialcontext yes jnp://localhost:9099 Conditioned from the App.Server TLGen 104 StarData Gmb V 2.8 3 initialcontextfactory yes org.jnp.interfaces.NamingC ontextFactory Conditioned from the App.Server 4 initialcontextpkgprefix yes org.jboss.naming:org.jnp.int erfaces Conditioned from the App.Server 5 contextkey no jboss.naming.client.ejb.cont ext JBoss7 6 contextvalue no true JBoss7 7 optionskey no Extra parameter für config JBoss7 8 optionvalue no false JBoss7 9 managermethods no Asset, Product, etc. List with all managers 10 methods no public 11 sequencegen yes SEQ_STORE Type from generator for primary key 13 format no 0 or 1 Default is 0 and is used “C” formatter style (siehe Listing 75) and by 1 is code formatter in “Java” style (siehe Listing 76) 14 import no true(default) Default is ‘false’. Do not use import in the class and all name is full qualified 15 data no false(default) Default is ‘false’. TLGen generates classes and interfaces data by default, if ‘true’, then only data classes. 16 list no true(default) Default is ‘true’, For Lists the class List is used, if ‘false’ arrays are used. 17 testRelation no true,true,true,true Relations in Test classes 18 earname yes demo The name from ear file 19 MappedNameRemote no Examples in the text Overwrites the standard generated attribute mappedname of the EJB3 annotation @Stateless/@Statefull in the Session-Beans 20 JNDIName no Examples in the text Overwrites the standard generated attribute name of the EJB3 annotation @Stateless/@Statefull in the Session-Beans. 21 JNDINameRemote no Examples in the text Overwrites the standard generated JNDI name for the Session-Beans and will be stored in the client Interface of the Session-Beans to call the remote Session-Bean. 22 level no Verwendet level Attribute für die lesefunktion 0, nur das Objekt selber, 1 auch seine Kinder, 2… TLGen 105 StarData Gmb V 2.8 23 persistence no True(default) true = value all domain will assume in persistence 24 persistenceUnit no false(default) Bei „true“ generiert nur rein persistence.xml auf der höchsten Ebene, false(default) generiert eine persistence.xml auf jede design Ebene 25 security no Ggeneriert security xmy 26 pathTest no “C:/Projects/ProjectRMA/source/help” Wenn vorhanden, generiert die Test Klasse an dieser Adresse 27 pathCriteria no „C:/Projects/ProjectRMA/source/criteria” Wenn vorhanden, generiert die Callback Klasse für Criteria an dieser Addresse 28 pathInterceptor no "C:/Projects/ProjectRMA/source/interceptor" Wenn vorhanden, generiert die Interceptor Klasse an dieser Addresse 29 enumsString no false(default) false – speichert die enums in der Datenbank als integer (standard) ab true – speichert die enums als String in der Datenbank ab Note ! in Default XML config file muss beim Tag <UmlControl den Attribut ‚enumType ‘ = VARCHAR2(Länge) eingetragen sein 30 createTyp no 0 0-(default) wird nach create die Daten lesen 1-wird flush(); und dann refresh(entity); aufgerufen Bei „true“ werden alle Metaund Callback Klassen für Criteria generiert. 31 criteria no 32 pathJsonData no 33 jsonData no false(default) Bei „true“ werden die JSon Dataobjects, die REST interface und die Callback Klassen für diese Interfaces generiert. 34 jsonLocking no false(default) Bei „true“ werden in JSon Data Objekt und auch die Variable von Versionierung (Locking) generiert, bei „false“ nicht 35 mappedByOtM no false(default) Der „true“-Parameter aktiviert die „mappedBy“-Annotation für „OneToMany“- und „MannyToMany“-Relationen in TLGen false(default) Wenn vorhanden, generieren die Callback Klassen für REST interfacess an dieser Adresse 106 StarData Gmb V 2.8 der Entity-Generierung. 36 restPort no 8080(default) Wenn vorhanden, wird für REST die Test Klasse als port verwendet, wenn nicht vorhanden, wird das Post „8080“ verwendet 37 foreignKeyIndex no false(default) false = no foreign key is not a index, true yes 38 jsonLocking no false(default) false = version variable (for locking) from data class in not generate in JSon data class, by true yes. 39 mapping no true(default) true = mapping the data classes with the JSon classes if this is generates, false = no 40 getManager no true(default) true = generate in “entity manager” class the method getEntityManager() for instance a “javax.persistence.EntityManager ” public class MyIntStack { private final LinkedList fStack; public MyIntStack() { fStack = new LinkedList(); } public int pop() { return ((Integer) fStack.removeFirst()).intValue(); } public void push(int elem) { fStack.addFirst(new Integer(elem)); } public boolean isEmpty() { return fStack.isEmpty(); } } Listing 75: „Java“ Code style public class MyIntStack { private final LinkedList fStack; public MyIntStack() { fStack = new LinkedList(); } public int pop() { return ((Integer) fStack.removeFirst()).intValue(); } public void push(int elem) TLGen 107 StarData Gmb V 2.8 { fStack.addFirst(new Integer(elem)); } public boolean isEmpty() { return fStack.isEmpty(); } } Listing 76: „C“ Code style Die JNDI-Namen der Session Beans werden von TLGen anhand der Attribute appserver=“{jboss|weblogic|websphere}“ (Generator-Tag), earname (Project-Tag) sowie der Package-Namen automatisch zusammengestellt und in den Attributen name und mappedName der Annotationen @Stateless/@Statefull gespeichert. Der JNDI-Name der Session-Bean sowie falls nötig, der Remote-JNDI-Name (jeder Application Server generiert beim „deployen“ andere Namen), werden in den Client-Interfaces der Session-Beans als statische Variablen gespeichert. Z.B. reicht bei einem bestimmten Application Server nur der Interface-Name der Session Bean, um diesen lokal im Application Server zu finden. Für einen Remote-Aufruf ist aber der Name aus dem EAR-Namen, seinem Package-JAR, dem Session-Bean Namen und dem InterfaceNamen nötig. Dies wird für die drei oben genannten Application Server automatisch generiert und mit der Klasse ServiceLocator aus den Commons Code-Beispielen automatisch bei einem Remote-Aufruf beachtet. Doch die automatischen Namen können mit Hilfe der Attribute MappedNameRemote, JNDIName und JNDINameRemote des Projekt Tags mit eigenen Definitionen überschrieben werden. Im Folgenden einige Beispiele womit der Generator die Ersetzungsnamen innerhalb von %...% ersetzt: - MappedNameRemote= "%earname%/%jndiname%/%remote%" - JNDIName="de.stardata.test.server.persistence.%package%.%classname%SessionBean" - JNDINameRemote="ejb/%earname%/%package%.jar/%interfacemanager%#%clientdata%" - JNDINameRemote="ejb/%earname%/%package%.jar/%classname%SessionBean#%clientdata%" - JNDINameRemote="ejb/%earname%/%package%.jar/de.stardata.test.server.persistence.%package%. %classname%SessionBean#de.stardata.test.client.bci.%package%.%classname%Bci" Ersetzungsnamen: - %interfacemanager% entspricht hier folgender Ersetzung: de.stardata.test.server.persistence.%package%.%classname%SessionBean - %interfacemanagershort% entspricht hier folgender Ersetzung: %classname%SessionBean - %clientdata% entspricht hier folgender Ersetzung: de.stardata.test.client.bci.%package%.%classname%Bci TLGen 108 StarData Gmb V 2.8 - %package% oder %classname% wird aus den jeweiligen Designs und der StandardKonfigurationsdatei bestimmt (siehe entsprechende Kapitel, Fehler! Verweisquelle konnte nicht gefunden werden.). 4.5.2.3 <Locator> Tag Diese Daten überschreiben die Daten von 4.4.2.3. 4.5.2.4 <Design> Tag <Design>-Elemente sind eine logische Fachgruppe innerhalb eines Projektes und können beliebig viele sein. Eine Design Komponente ist als eine fachspezifische logische Einheit gedacht. Kinder-Elemente können mehrere Session Beans, Datenobjekte, Manager- und Entity Beans sein. Der <Design>-Tag hat folgendes Attribut: name, ist der Name für Design Komponente archive, ist ein int und hat folgende Werte: o 0 = archive für diese als „jar“ Datei o 1 = archive als „war“ Datei o 2 = archive als „jar“ und „war“ Datei criteria (dfault false), wenn „true“ generiert für dieses design alle criteria und meta Klassen. 4.5.2.4.1 Regel für package Generierung Empfohlene path Struktur ist: "Netz“.“Firma-Name“.%project%.Komponent.%package%.%classname%Endung Wo: „Netz“ ist das nationale Netz, z.B. für Deutschland „de“ „Firma-Name“ ist der Name der Firma, z.B. für „Demo“ Beispiel ist „stardata“ „Komponent“ ist eine Programmkomponente, z.B „business“ oder „server.persistence“ „%package%“ ist eine Fach-Logik definierte Komponente, z.B, „product“, „user“ „%classname%“ ist der Java Klassen Name, z.B. „Product“ „Endung“ ist eine vordefinierte Endung, die Hilfe für eine bessere Codestrukturierung ist g, z.B. „Entity“, „Session“ 4.5.2.4.2 <Commentary> Tag Siehe Kap. 3.12 TLGen 109 StarData Gmb V 2.8 4.5.2.4.3 <Class> Tag Dieser Tag wird zur Generierung von Business Daten-Klassen verwendet. Dessen Daten überschreiben die Daten von 4.4.2.4. Ist ein optionales Element. Dieses Element generiert Daten-Klassen und Interfaces und hat folgende Attribute: name = "de.stardata.demo.business.product..data.%classname%Data| de.stardata.demo.business.product.dataif.%classname%DataIf" hat zwei Teile, einen für die Klassen und einen für die Interfaces, getrennt durch „|“Für die automatischen Namen sind Platzhalter verwendet worden: o %classname% dieses Attribut wird automatisch vom Generator durch den Objekt Namen aus dem Domain Modell ersetzt oder den Tabellen-Namen oder geänderten Tabellen-Namen (durch Rules), welche aus der Datenbank gelesen wurden (z.B. bei einem Legacy-Projekt). type = „public“, d.h. Klassen und Interfaces sollen public sein. Dieser Tag hat zwei Kinder-Elemente-, die optional sind, und folgende Standard-Einstellungen: <Extends name="com.tlgen.common.data.BaseData"/>, kann eigene super Class verwenden. <Extends name="com.tlgen.common.data.BaseDataIf" type="interface"/> 4.5.2.4.4 <Entity> Tag Dieser Tag wird verwendet, um den Generator mit Informationen über die Entities zu versorgen. Er ist optional und überschreibt die Daten von 4.4.2.5, falls vorhanden. Der Entity-Tag hat folgende Attribute: name = "de.stardata.server.persistence.product.entity.%classname%Entity" (Beschreibung wie in 4.5.4.2.1) seqstrategy="SEQUENCE" ist Default-Wert. Dieses Attribut ist für die automatische Generierung von Primary Key notwendig (z.B. Oracle). Dieser Tag hat folgende Kinder-Tags, die optional sind: <Implements> mit Attribute name="java.io.Serializable" <Extends> mit Attribut name="com.tlgen.common.ejb.entity.BaseEntityBean" <Annotation>, dieser Tag ist optional und der Generator generiert folgende Annotationen für die Entities: o TLGen "javax.persistence.Entity" 110 StarData Gmb V 2.8 o "javax.persistence.Table" der Generator übernimmt automatisch den TabellenNamen o "javax.persistence.SequenceGenerator" Folgende Kinder-Tags sind möglich (mit Beispiel der Standard-Klasse): <Extends name="com.tlgen.common.ejb.entity.BaseEntityBean"/> 4.5.2.4.5 <Manager> Tag Dieser Tag versorgt den TLGen Generator mit Informationen für die Generierung von ManagerBeans und hat folgende Attribute: name="eu.stardata.server.persistence.product.manager.%classname%Manager (Beschreibung wie in 4.5.4.2.1) transactiontype = "JTA“(Standard-Wert) exception = "com.tlgen.common.exception.PersistenceException" (Standard-Wert) Dieser Tag hat folgende Kinder-Tags, die optional sind: <Extends> (Standard-Attribut name=" com.tlgen.common.ejb.manager.BaseManager ") <Annotation>, dieser Tag ist optional und der Generator generiert z.B. folgende Annotationen für die Entities: o "javax.ejb.Stateless" o "javax.ejb.Local" Die Manager Fields-Beschreibung siehe unter Kap 4.5.2.6 4.5.2.4.5.1 Feldern (Variable) für Entity Manager Folgende Felder (siehe auch 4.5.2.6) werden für eine Manager Klasse generiert: m_manager mit Type „javax.persistence.EntityManager“. Dieses Field hat eine Annotation von type (javax.persistence.PersistenceContext) und ein Parameter von type String (MANAGER_NAME) (siehe 4.5.2.4.5). m_“SQL Name“, sind die Fields, die die generierte „Native“ oder „Neimed“ SQL beinhalten, siehe Listing 77: SQL Fields private String m_countCustomer = "select count(o) from CustomerEntity o"; private String m_NativeQuery00 = "SELECT * FROM CUSTOMER WHERE CUSTOMER_ID = ?"; private String m_findByName = "select o from CustomerEntity o where o.lastName = :lastName"; Listing 77: SQL Fields TLGen 111 StarData Gmb V 2.8 4.5.2.4.5.2 Methoden für Entity Manager Wie in 3.4.1 bereits erwähnt, gibt es drei Möglichkeiten bzw. Methoden um die Manager zu generieren, auch die internen Methoden des Managers, Standard Remote-Methoden oder eine user definierte Methode für die Persistente-Datenverwaltung. Die ersten zwei sind in 4.5.2.5 beschrieben. Die dritte Art von Manager Methoden sind die Methoden mit Methodentyp methodtype=6, 7, 8 und 9 (siehe ab 4.5.2.4.5.2.1 bis 4.5.2.4.5.2.6). Diese Methoden definieren ein SQL Query und brauchen eine oder mehrere <Parameter>-Tags für die Beschreibung der Input-Daten sowie ein <Sql>-Tag. Für diese Methoden sind folgende Attribute notwendig: name=“NamedQuery01“, ist der Methoden Name manager=“Formular“, benennt den Manager und wo die Methode generiert wird. mapping=“false“, besagt, ob eine Mapping notwendig ist oder nicht (Default ist „false“, aber für die Native-SQLs ist fast immer eine Mapping nötig) return=“java.util.List<%interfacedata%>“, ist der erwartete Return Type. Dieser Platzhalter wird vom Generator durch das richtige Interface ersetzt. methodtype= „6“, „7“, „8“, „9“, „10“ oder „11“. Im Folgenden erfolgt die Beschreibung der Methoden-Typen. 4.5.2.4.5.2.1 Entity Menager Methoden Typ 6 Method-Typ 6 sind Methoden, die für EJB-SQL gedacht sind (Listing 78) <Method name="findByNameAndOffer" parameter="java.lang.String" return="%interfacedata%[]" manager="Product" methodtype="6"> <Parameter name="name" fullName="name" type="java.lang.String" /> <Parameter name="productOfferingId" fullName="productOfferingId" type="java.lang.String" /> <Sql name="getNameAndOffer" sql="select u from ProductEntity u where u.name = :name and u.productOfferingId = :productOfferingId" /> </Method> Listing 78: Methode Type „6“ in der Konfigurationsdatei In Beispiel, Listing 78 wird bzw. werden eine oder mehrere Product Objekt(e) nach dem Produkt-Namen und einer ID productOfferingId gesucht. TLGen 112 StarData Gmb V 2.8 TLGen generiert daraus im Manager Bean der Klasse Product Manager ein Feld und eine Zugriffsmethode: private String m_getNameAndOffer = "select u from ProductEntity u where u.name = :name and u.productOfferingId = :productOfferingId"; /** * Manager method "findByNameAndOffer()" * @param name * @param productOfferingId * @return * @throws PersistenceException */ public ProductDataIf[] findByNameAndOffer(String name, String productOfferingId) throws PersistenceException { try { ProductDataIf[] arrayData = null; List<?> list = m_manager.createQuery(m_getNameAndOffer).setParameter("name",name). setParameter("productOfferingId",productOfferingId).getResultList(); if(list != null && list.size() > 0) { arrayData = new ProductDataIf[list.size()]; int idx = 0; for(Object entity : list) { if(entity != null) { arrayData[idx++] = ((ProductEntity)entity).callProduct(); } } } return arrayData; } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } Listing 79: Methode Typ “6” in Entity Manager-Klasse 4.5.2.4.5.2.2 Entity Menager Methoden Typ 7 Methoden von Typ 7 sind fürNamed SQLs gedacht (siehe Listing 8080). <Method name="NamedQuery02" manager="Formular" return="java.util.List&#60;%interfacedata%&#62;" methodtype="7"> <Parameter name="developName" type="java.lang.String" /> <Sql name="Formulartest" sql="SELECT f FROM FormularEntity f WHERE f.developer LIKE :developName" /> </Method> Listing 80: Methode Type “7” in der Konfigurationsdatei TLGen 113 StarData Gmb V 2.8 TLGen generiert daraus eine Methode in der Manager-Klasse (Listing 81) und eine Annotation @javax.persistence.NamedQueries in der dazugehörigen Entity-Klasse (Listing 82): /** * Manager method "NamedQuery02()" * @param developName * @return * @throws PersistenceException */ public List<CoFormularDataIf> NamedQuery02(String developName) throws PersistenceException { try { List<CoFormularDataIf> list = null; List<?> entityList = m_manager.createNamedQuery("sqlFormulartest"). setParameter("developName",developName).getResultList(); if(entityList != null && entityList.size() > 0) { list = new ArrayList<CoFormularDataIf>(); for(Object entity : entityList) { if(entity != null) { list.add(((FormularEntity)entity).callFormular()); } } } return list; } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } Listing 81: Methode Type “7” Entity Manager-Klasse @NamedQueries ({ @NamedQuery( name = "sqlFormulartest", query = "SELECT f FROM FormularEntity f WHERE f.developer LIKE :developName") }) Listing 82: Methode Typ “7” in der Entity-Klasse 4.5.2.4.5.2.3 Entity Menager Methoden Typ 8 Methoden von Typ „8“ werden für die Native SQL Queries verwendet. Ein Beispiel für den Eintrag in die Konfigurationsdatei befindet sich in Listing 83. <Method name="NativeQuery02" manager="Formular" mapping="true" return="java.util.List&#60;%interfacedata%&#62;" methodtype="8"> <Sql sql="SELECT * FROM CORE_FORMULAR, CORE_PAGE WHERE CORE_FORMULAR. FORMULAR_ID = CORE_PAGE.FORMULAR_ID AND CORE_FORMULAR.FORMULAR_ID = ?" /> </Method> Listing 83: Methode Typ „8“ in der Konfigurationsdatei TLGen 114 StarData Gmb V 2.8 Der notwendigen Parameter für diese Methode werden von TLGen automatisch aus den Datenbank-Informationen heraus generiert. TLGen generiert aus diesem Eintrag in der Konfigurationsdatei eine Entity-Class (Listing 84) und die dazugehörige Daten-Klasse sowie deren Interfaces (fals verwendet) (Listing 85). package eu.stardata.server.persistence.formular.entity; import eu.stardata.business.form.dataif.CoPageDataIf; import javax.persistence.NamedNativeQueries; import javax.persistence.SqlResultSetMapping; import eu.stardata.business.form.dataif.CoNativeQuery02DataIf; import javax.persistence.NamedNativeQuery; import javax.persistence.EntityResult; import javax.persistence.SqlResultSetMappings; import javax.persistence.Column; import eu.stardata.server.persistence.formular.entity.FormularEntity; import eu.stardata.server.persistence.formular.entity.PageEntity; import eu.stardata.business.form.dataif.CoFormularDataIf; import javax.persistence.Id; import javax.persistence.Entity; @Entity @NamedNativeQueries ({ @NamedNativeQuery( name = "NativeQuery02", query = "SELECT * FROM CORE_FORMULAR, CORE_PAGE WHERE CORE_FORMULAR.FORMULAR_ID = CORE_PAGE.FORMULAR_ID AND CORE_FORMULAR.FORMULAR_ID = ?", resultSetMapping = "NativeQuery02") }) @SqlResultSetMappings ({ @SqlResultSetMapping(name = "NativeQuery02", entities = { @EntityResult(entityClass = FormularEntity.class ), @EntityResult(entityClass = PageEntity.class ) } ) }) public class NativeQuery02Entity { private static final long serialVersionUID = 597104846; // Entity data field private CoNativeQuery02DataIf m_nativeQuery02 = null; // constructors /** * Default Constructor */ public NativeQuery02Entity() { } /** * Constructor * @param arg */ public NativeQuery02Entity(CoNativeQuery02DataIf arg) { m_nativeQuery02 = arg; fillNativeQuery02(); } TLGen 115 StarData Gmb V 2.8 // Helper methods /** * Helper Method "makeNativeQuery02()" */ public CoNativeQuery02DataIf makeNativeQuery02() { if(m_nativeQuery02 == null) { m_nativeQuery02 = new eu.stardata.business.form.data.CoNativeQuery02Data(); } return m_nativeQuery02; } /** * Helper Method "fillNativeQuery02()" */ public void fillNativeQuery02() { } /** * Helper Method "addNativeQuery02()" */ public void addNativeQuery02() { } /** * Helper Method "callNativeQuery02()" */ public CoNativeQuery02DataIf callNativeQuery02() { // return the data object return makeNativeQuery02(); } // Methods from class public CoFormularDataIf getFormular() { return makeNativeQuery02().getFormular(); } public void setFormular(CoFormularDataIf arg) { makeNativeQuery02().setFormular(arg); } public CoPageDataIf getPage() { return makeNativeQuery02().getPage(); } public void setPage(CoPageDataIf arg) { makeNativeQuery02().setPage(arg); } @Id @Column(name = "FORMULAR_ID") public long getFormularId() { return makeNativeQuery02().getFormularId(); } public void setFormularId(long arg) { makeNativeQuery02().setFormularId(arg); } } Listing 84: Methode Typ „8“ in Entiy-Klasse TLGen 116 StarData Gmb V 2.8 package eu.stardata.business.form.data; import eu.stardata.business.form.dataif.CoPageDataIf; import eu.stardata.business.form.dataif.CoFormularDataIf; import eu.stardata.business.form.dataif.CoNativeQuery02DataIf; import com.tlgen.common.data.BaseData; public class CoNativeQuery02Data extends BaseData implements CoNativeQuery02DataIf { private static final long serialVersionUID = 883471837; // Methods from columns private long m_formularId; // Methods from class private CoFormularDataIf m_formular; private CoPageDataIf m_page; // Methods from columns public long getFormularId() { return m_formularId; } public void setFormularId(long arg) { m_formularId = arg; } // Methods from class public CoFormularDataIf getFormular() { return m_formular; } public void setFormular(CoFormularDataIf arg) { m_formular = arg; } public CoPageDataIf getPage() { return m_page; } public void setPage(CoPageDataIf arg) { m_page = arg; } } und Daten interface: package eu.stardata.business.form.dataif; import eu.stardata.business.form.dataif.CoPageDataIf; import eu.stardata.business.form.dataif.CoFormularDataIf; import com.tlgen.common.data.BaseDataIf; public interface CoNativeQuery02DataIf extends BaseDataIf { // Methods from columns public abstract long getFormularId(); public abstract void setFormularId(long arg); // Methods from class public abstract CoFormularDataIf getFormular(); public abstract void setFormular(CoFormularDataIf arg); public abstract CoPageDataIf getPage(); public abstract void setPage(CoPageDataIf arg); } Listing 85: Daten-Klasse für die Methode Typ „8“ TLGen 117 StarData Gmb V 2.8 4.5.2.4.5.2.4 Entity Menager Methoden Typ 9 Liste Objekte in DB mit createQuery() EntityManager Methode. 4.5.2.4.5.2.5 Entity Menager Methoden Typ 10 Liste Objekte in DB mit createNativeQuery() EntityManager Methode. 4.5.2.4.5.2.6 Entity Menager Methoden Typ 11 Methoden von Typ „11“ werden für die Criteria verwendet. Ein Beispiel für den Eintrag in die Konfigurationsdatei und in Entity Manager befindet sich in Listing 45. 4.5.2.4.5.3 Manager Interfaces TLGen generiert für jede Manager-Klasse automatisch ein Interface, notwendig für die Verwendung von Entity Manager Beans (siehe 3.4.2). 4.5.2.4.6 <Session> Tag Dieser Tag versorgt den Generator mit allgemeinen Informationen für die Generierung einer Session Bean. Diese Daten überschreiben die Daten aus 4.4.2.10. TLGen kann in zwei Varianten verwendet werden: 1. Die Code-Generierung aus einem UML Domain-Modell ist besonders für neue Projekte geeignet. Um den Zeit- und Kostenaufwand zu minimieren, sollten für die Generierung die meisten Informationen über die Standard Konfigurationsdatei und nur die spezifischen Informationen wie Name, Native Queries und Test Klassen über die Konfigurationsdatei erfolgen. 2. Für die Code-Generierung aus einer existierenden Datenbank ist die Verwendung der Konfigurationsdatei intensiver nötig als die der Standard Konfigurationsdatei, da die gelesenen Daten über die Tabellen aus der Datenbank auf fachlogische Kriterien über die Design Session Beans verteilt werden müssen. Das Session Bean-Element kann folgende Attribute verwenden: TLGen 118 StarData Gmb V 2.8 name="de.stardata.demo.server.persistence.product.ProductSessionBean", ist der vollständige Klassenname (Pfad und mit Platzhalter für alle Session Beans). managername="managerProduct", gibt Informationen dem manager, die für die „persistence.xml“-Datei notwendig sind (siehe 4.5.2.4.5). transactiontype="JTA" gibt die Information für die Transaction-Typ. Session Bean hat z.B. folgende mögliche Annotationen: name="javax.ejb.Stateless", oder „javax.ejb.Stateful“ name="javax.ejb.Remote" name=” javax.interceptor.Interceptors”, nur wenn die Session Beans eine InterceptorKlasse verwenden. Wenn die Session Bean als Web Service oder als Timer Service verwendet wird, können auch andere Annotationen verwendet werden (siehe 4.5.2.4.6.4, 4.5.2.4.6.5). 4.5.2.4.6.1 Methoden für Session Bean Session Bean übernimmt alle oder nur die auserwählten Methoden von Entity Manager, die über die Session Bean aufgerufen werden (Details in 4.5.2.4.5). Diese Methoden haben den Namen der Methode und dazu noch den Manager-Name; z.B. die Methode „findByPrimaryKey“ für das Manager Formular hat den Namen „findByPrimaryKeyFormular“. Diese Zusammensetzung von Namen ist notwendig, weil der Name „findByPrimaryKey“ in mehrere Manager-Beans, verwaltet über diese Session Beans, vorhanden sein kann. Dieser Name wird bis zum Client hindurch gleichbleibend verwendet. 4.5.2.4.6.2 <Client> tag Ist ein Kindelement der Session Beans und dient zur Generierung von Client-Aufrufen. Auch dieser Tag ist optional. Dieser Tag hat folgende Attribute mit folgenden Standard Werten: name="de.stardata.demo.client.bci.product.ProductBci" exception = "com.tlgen.common.exception.PersistenceException" Aus diesen Informationen generiert TLGen ein Interface (Listing 86: Client Interface), notwendig für eine Session Bean, und eine Factory Klasse, welche den Aufruf seitens Client erleichtert (Listing 87): package de.stardata.demo.client.bci.product; TLGen 119 StarData Gmb V 2.8 import javax.ejb.Remote; import de.stardata.demo.business.product.dataif.ProductPriceDataIf; import de.stardata.demo.business.product.dataif.ProductAttributeDataIf; import java.lang.String; import de.stardata.demo.business.product.dataif.ClassificationDataIf; import de.stardata.demo.business.product.dataif.ProductRelationDataIf; import com.tlgen.common.exception.PersistenceException; import de.stardata.demo.business.product.dataif.ProductDataIf; @Remote public interface ProductBci { // Client interface Fields public final static String JNDI_NAME = "de.stardata.demo.server.persistence. product.ProductSessionBean"; public final static String MANAGER_NAME = "managerProduct"; public final static String EAR_NAME = "demo"; ….. public ProductDataIf createProduct(ProductDataIf arg) throws PersistenceException; public ProductDataIf findByPrimaryKeyProduct(ProductDataIf arg) throws PersistenceException; public void removeProduct(ProductDataIf arg) throws PersistenceException; …. } Listing 86: Client Interface package de.stardata.demo.client.bci.product; import de.stardata.demo.client.bci.product.ProductBci; import com.tlgen.common.exception.PersistenceException; import com.tlgen.common.bci.BciFactory; public class ProductBciFactory extends BciFactory { private static final long serialVersionUID = 1033431309; /** * getProductBci() */ public static synchronized ProductBci getProductBci() throws PersistenceException { return (ProductBci)getBciImplementation(ProductBci.class); } } Listing 87: Factory Client Class Mit Hilfe des Interface und der Factory-Klasse ist der Aufruf seitens Client sehr einfach (Listing 88): ProductDataIf m_clProduct = new ProductData(); // Versorgung von Product Attribute mit Werten ….. ProductBci factory = ProductBciFactory.getProductBci(); // Speichern von Product Object in die Datenbank m_clProduct = factory.createProduct(m_clProduct); // Lesen von den Product Object für ein Id clProduct.setProductId(10); TLGen 120 StarData Gmb V 2.8 ProductDataIf product = factory.findByPrimaryKeyProduct(m_clProduct); Listing 88: Client call‘s 4.5.2.4.6.3 <Xml-persistence> Tag Der Tag setzt die Properties der persistence.xml, z.B. notwendig in einer EAR, um die eigene Applikation in einem Application Server zu installieren. Diese Werte sind vom Applikation Server abhängig. Statt der Attribute value wird hier type für <Property> verwendet. <Property name="hibernate.dialect" type="org.hibernate.dialect.Oracle10gDialect" /> Beispiel: JBoss Version 5.x brauchte bei Verwendung der Oracle-Datenbank Version 11.x die folgende Information, um eine Datenbank-Verbindung aufzubauen: <Property name="hibernate.dialect" type="org.hibernate.dialect.Oracle10gDialect" /> Diese Daten überschreiben komplett oder nur teilweise die Daten aus 4.4.2.10.3. 4.5.2.4.6.4 < Timerservice> Tag Ein Timer Service kann mit einer Session Bean oder Message Driven Bean verwendet werden. Damit kann eine Methode entweder an einem bestimmten Tag und zu einer bestimmten Zeit aufgerufen werden oder aber alle n Sekunden. Diese Methode über eine Callback Class kann einen Prozess steuern, starten, periodisch aufrufen oder stoppen. Timer Service kann in drei unterschiedlichen Varianten verwendet werden: Voll automatisch, in diesem Fall sollten Start, Stopp-Zeit und die periodische Wiederholung initialisiert werden (Attribut type=“auto“). Start und Stopp-Zeit wird durch einen Client-Aufruf gesteuert (Attribut type=“manuell“, das ist die Default–Einstellung). Man verwendet die automatische und die manuelle Steuerungsmöglichkeit (Attribut type=“merge“) (siehe 3.8). Es folgt eine Beschreibung der notwendigen Konfigurationsdaten. Folgende Kinderelemente sind für diesen Tag notwendig: <Variable> (Daten-Struktur dieses Tags siehe 4.5.2.6) für folgende Felder: o TLGen timerService, mit der Annotation „javax.annotation.Resource“ und dem vartype = "javax.ejb.Timerservice", wird für die Zeit-Steuerungs Methoden benötigt. 121 StarData Gmb V 2.8 o <Method> (Daten-Struktur dieses Tags siehe 4.5.2.5) sind Methoden, die der Timer Service benötigt. Folgende Methoden sind notwendig: o Eine Kommando Variable mit folgende Daten: vartype = „string“, um den Timerservice zu beenden. name = „init%Name%“, notwendig für die automatische Verwendung von Timer Service und dessen Initialisierung mit folgenden notwendigen Parameter (siehe Listing 43): <Parameter> name=“start“, definiert den Beginn dieser Service, type=“date“ ist die Start-Zeit <Parameter> name=“stop“, definiert das Ende dieser Service, type=“date“, ist die Ende-Zeit <Parameter> name=“repeat“, definiert die Wiederholungsrate; type=“long“, ist die Wiederholung von Zeit in Sekunden. o name = „timeout“, wird bei beiden Varianten der Timer Service-Verwendung benötigt. Diese hat eine Annotation „@javax.ejb.Timeout“ und ruft die Callback Methode „timeout“ auf. o name = „start%Name%“, startet diese Service nach einem Client-Aufruf, ist für die manuelle Timer Service-Verwendung notwendig o name=“stop%Name%“, stoppt manuell den Prozess. <Callback> ist eine Klasse, deren Methoden von Timer Service Methoden aufgerufen werden, um Prozesse zu steuern. Werden mehrere Methoden verwendet, sollen die Namen dieser Methoden mit den Namen der Timer Service-Methoden identisch sein. Diese Klasse wird vom Generator generiert. Die Inhalte dieser Methoden müssen per Hand programmiert werden. Dieser Tag hat folgende Attribute und Kinderelemente: o Name (Attribute) = „eu.stardata.client.monitor.CallBackServiceMonitor“, ist der Callback Klassenname o Path (Attribute) = “C:/Project-TLGen-2.8/source/test”, ist der Ort, wo diese Klasse generiert wird.<Method> (Kindelement); ist die aufzurufende Methode und kann mehrmals vorkommen. <Method type="public void" name="initMonitor"> <Parameter type="15.04.2011 10:30" name="start"/> <Parameter type="16.05.2011 9:30" name="stop"/> <Parameter type="600" name="repeat"/> </Method> Listing 89: Konfigurationsdatei-Eintrag für eine Timer Service-Klasse 4.5.2.4.6.5 < Web Service> Tag Ein Web Service ist ein beliebiger Service (z. B. eine Session Bean), der von einem Client über z.B. das Internet aufgerufen werden kann. Es werden zwei Arten von Web Service unterschieden, RPC (Remote Procedure Call) und DOCUMENT. RPC , ein Aufruf einer Methode (z. B. eine Methode von einem Session-Bean) über Web. TLGen 122 StarData Gmb V 2.8 TLGen generiert für diese Services den Client, den Web Service und eine Callback-Klasse (siehe 3.8), falls diese nötig ist. 4.5.2.4.6.6 <Interceptor> Tag Dieser Tag wird für die Generierung von Session Bean Interceptoren verwendet und hat folgende Attribute: name=“eu.stardata.server.persistence.formular.TimeFormular“, ist der Interceptor Klassen-Name path=” C:/Project-TLGen-2.8/source/generated”, ist der Ort, wo die Interceptor Klasse generiert wird. Ein Interceptor kann eine oder mehrere Methoden haben (siehe 4.4.2.10.4). 4.5.2.4.6.7 <Freeclass> Tag Dieses Element wird für die Generierung einer Klasse, die als Schnittstelle zu dem Programmteil, welcher die Fachlogik beinhaltet, verwendet. Der Inhalt dieser Klasse muss selber implementiert werden. Falls der Generator diese Klasse in dem angegebenen Pfad findet, generiert er, abhängig vom Attribut „merge“, die Differenz aus beiden, ohne die vorhandenen Methoden zu löschen. Folgende Attribute werden für diesen Tag verwendet: name=“eu.stardata.server.persistence.user.MappingEngine“, ist der Klassen-Name mit Pfad. path=” C:/Project-TLGen-2.8/source/user”, ist der Ort, wo diese Klasse generiert wird. merge, dieses Attribut hat folgende Werte: o merge = 0, TLGen generiert diese Klasse immer wieder neu. o merge = 1, diese Klasse wird, nur wenn sie nicht existiert, generiert. o merge = 2, wird eine neue Klasse generiert und mit dem vorhandenen per Hand implementierten Code zusammengefasst. Diese Klasse kann eine oder mehrere Methoden haben. 4.5.2.4.6.8 <Callback> Tag Eine <Callback> Tag (siehe) kann folgende Attribute verwenden: TLGen name ist der komplette Klassen-Name, z.B. „eu.stardata.demo.rest.CallBackRest“ callbackType kann folgende Inhaltswerte (Strings) haben o „Session“, für alle „Timerservice“, “REST“, und „Web Service“ o „Class“ ist der Default-Wert 123 StarData Gmb V 2.8 path ist die Adresse wo diese Klasse generiert wird, z.B. „C:/Projects/demo“ merge, siehe 3.8 4.5.2.4.7 < Message Driven> Tag TLGen verwendet die Daten in diesem Element für die Generierung von Message Driven Bean. Diese hat ein einziges Attribut; name = “Chat“ und zwei Kinderelemente <Client> (siehe 4.5.2.4.7.1) und <Bean> (siehe 4.5.2.4.7.2). Ein Beispiel für die Konfigurationsdatei ist in Fehler! Verweisquelle konnte nicht gefunden werden. und für den generierten Code in 7.12 zu finden. 4.5.2.4.7.1 <Client> Tag für Message Driven Bean Der Client-Tag hat folgende Attribute: name=“eu.stardata.client.bci.chat.ChatBci| eu.stardata.client.message.chat.ChatMessageClient“, hat zwei Teile, der erste Teil beinhaltet den vollständigen Namen für das Client-Interface und der zweite Teil für die Client-Klasse. Der <Client> Tag benötigt zwei Kinderelemente: 1. <Commentary>, wird benutzt, um die Message Driven Bean zu beschreiben, 2. <Variable> (für die Daten Struktur siehe 4.4.2.14), beschreibt mehrere Felder: a. name=“JNDI_NAME_SENDER“, ist das Senderfeld und braucht noch ein Attribut content=“gueue/queueA“, JNDI für den Sender (der Inhalt ist frei wählbar) und ein Attribut comtype=“0“. Dieses Feld ist Pflicht. b. name=“JNDI_NAME_RECEIVER“, ist das Senderfeld und braucht noch ein Attribut content=“topic/topicA“, JNDI für den Receiver (der Inhalt ist frei wählbar) und ein Attribut comtype=“1“. Dieses Feld wird, nur wenn eine Antwort vom Server notwendig ist, verwendet. c. name=“ACKNOWLEDGE_MODE“, dieses Field bestimmt wie der App.Server diese Nachricht quittiert oder überhaupt nicht. Im Attribut content sind zwei Eintragungen möglich, „Auto-acknowledge“ als Standard, bei diesem quittiert der APP.Server sofort die erhaltene Nachricht und „Dups-ok-acknowledge“, bei diesem lässt sich der Server für die Quittierung etwas Zeit. Bemerkung: comtype Attribut kann folgenden Inhalt haben: „0“ oder „queue“ für „Point-ToPoint“ Kommunikation und „1“ oder „topic“ für eine „Publish-and-Subscribe“ Kommunikation. 4.5.2.4.7.2 <Bean> Tag für Message Driven Bean TLGen 124 StarData Gmb V 2.8 Dieser Tag hat ein Attribut und mehrere Kinder-Tags. Dessen Attribut ist ein vollständiger Name, z.B. name=“eu.stardata.server.message.chat.ChatMessageBean“. Die Message Driven Bean braucht eine Annotation, „@javax.ejb.Messag, um die Kommunikationeigenschaften zu definieren. Diese Informationen können über die Konfigurationsdatei dem Generator übergeben werden. <Annotation name="javax.ejb.ActivationConfigProperty"> <Parameter type="MessageFormat = 'ChatMessage'" name="messageSelector"/> </Annotation> Listing 90: Message Driven Bean Folgende Parameter werden in der Konfigurationsdatei nach dem Muster von Listing 44 definiert werden: 1. Parameter type = "%connectclass%" name = "destinationType". Das Attribut type kann “javax.jms.Queue” oder “javax.jms.Topic” sein und der Platzhalter wird vom Generator mit dem comtype Attribut vom Client ersetzt. 2. Parameter type = "%connect%" name = "destination"; der Platzhalter wird vom Generator mit Variable “JNDI_NAME_SENDE ” Inhalt ersetzt, in unserem Beispiel mit „gueue/queueA“. 3. Parameter type = " MessageFormat = 'ChatMessage' " name = "messageSelector"; über diesen Parameter für Kommunikation-Properties kann bestimmt werden, welche Nachrichten der Bean zugestellt werden. 4. Parameter type="Auto-acknowledge" name = "acknowledgeMode" sind optional. 5. Parameter type="NonDurable" name="subscriptionDurability" sind Standard und für wichtige Nachrichten, die unbedingt zugestellt werden müssen, sollte der type = “Durable” gewählt werden. Die Namen der zuvor beschriebenen Parameter sind nicht wählbar. 4.5.2.4.7.3 <Callback> Tag für Message-Driven Bean Dieser Tag hilft dem Generator eine Callback-Klasse zu generieren, wo dann die Fachlogik programmiert werden kann: Diese Klasse wird jederzeit, wenn ein Message zugestellt wird, aufgerufen. Folgende Attribute sind für diesen Tag zu verwenden: o name (Attribute) = „eu.stardata.client.chat.CallBackServerChatMessage“, ist der Callback Klassen-Name. o path (Attribute) = “C:/Project-TLGen-2.5/source/test”, ist der Ort, wo diese Klasse generiert wird. o merge (Attribute) siehe 3.8 Die Callback Class kann eine oder mehrere Methoden haben (Listing 91): TLGen 125 StarData Gmb V 2.8 <Method name="callBackChat" return="javax.jms.Message"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter name="message" type="javax.jms.Message"/> </Method> Listing 91: Callback-Klasse für eine Message Driven Bean 4.5.2.4.8 <Test> Tag Mit Hilfe des <Test>-Tags generiert TLGen eine Test-Klasse, abgeleitet vom „junit.framework.TestCase“. Folgende Attribute können für diesen Tag verwendet werden: name = „eu.stardata.client.test.formular.FormularWriteReadTest“ ist der Name der TestKlasse und ein Pflicht-Feld, filename = “eu.stardata.client.test.formular.TestDataForFormular”; Ist dieses Attribut vorhanden, wird eine XML Datei mit der Datenstruktur der Test-Klasse generiert. Existiert diese Datei schon, werden die dort gespeicherten Daten für die Initialisierung der Attribute der Testklasse für die „create“-Test-Methode verwendet (z.B. ein Datenbank-Insert). 4.5.2.4.8.1 Generierung von Methoden für Test-Klassen Über die Test-Methoden werden die Aktionen „create“ für die Speicherung eines neuen Objekts in der Datenbank, „update“ für die Änderung eines Objekts, „find%Name%“ für das Lesen eines oder mehrerer Objekt bzw. Objekte und „delete“ für das Löschen eines Objekts in der Datenbank gesteuert. Die Daten-Struktur der Methoden siehe 4.5.2.5. 4.5.2.4.9 <Dbtable> Tag Dieser Tag wird nur für die Generierung von Code auf Basis einer Datenbank verwendet und hilft zur Gruppierung bestimmter Tabellen einer Design/Session Bean. Das einzige Attribut ist name, welches gleich mit dem Tabellen-Namen sein muss. TLGen liest alle anderen Informationen über dieseTabelle. Für jede Tabelle werden seitens TLGen eine Daten-Klasse und deren Interface generiert (siehe 3.1). In diesem Tag können Methoden, die nicht für die Datenpersistenz sondern nur für die Fachlogik verwendet werden, mit Hilfe von <Method>-Tag definiert werden (4.4.2.13). Hier können auch die Relationen zwischen den Tabellen mit Hilfe des <Relation>-Tags definiert werden (4.5.2.4.9.1). 4.5.2.4.9.1 <Relation> Tag, Verwendung von Relationen TLGen 126 StarData Gmb V 2.8 Ein Relation Tag hat folgende Attribute: 1. name = „OneToMany“ definiert einen von der vier Relation-Typen: „OneToOne“, „OneToMany“, „ManyToOne“ und „ManyToMany“, 2. table = „Table-Name“ ist der Tabellen-Name mit dem diese Relation durchgeführt wird 3. cascade = „Cascade-Type“; Folgende mögliche Cascade-Typen: „PERSIST“, „MERGE“, „REMOVE“, „REFRESH“ oder „ALL“. 4. optional = „true“ oder „false“, (siehe 1) 5. fetchType = „EAGER“ oder „LAZY“ (siehe 1) 6. direction = „true“, „false“ ist eine Standard-Einstellung und gilt nur für die Relationen „OneToOne“ und „ManyToMany“, wo ersichtlich ist, was für eine Tabelle die „Main“Table (Master/Slave-Prinzip) ist. Der <Relation>-Tag hat zwei Kinder-Tags: 1. <JoinColumn> versorgt den Generator mit den Daten über die beteiligten Spalten (Columns) zu dieser Relation. Dieser hat folgende Attribute: a. name = „Column-Name“ ist der eigene Spalten-Name für diese Relation. b. referencedColumnNam = „Column-Name“ ist der Spalten-Name anderer Tabellen, beteiligt bei dieser Relation. c. insertable = „true/false“ d. updatable = „true/false“ e. nullable = „true/false“ 2. <JoinTable> versorgt den Generator mit Informationen über die dritte Tabelle (notwendig für eine „ManyToMany“ Relation). Dieser hat folgende Attribute: a. name ist der Tabellen-Name b. catalog ist der Datenbank-Katalog c. schema ist das Datenbankschema des Users Dieser Tag hat zwei Kinderelemente: 1. <JoinColumn>, siehe Punkt 1, wo name der Spaltenname ist. 2. <InverseJoinColumn> die Spalte der anderen Tabelle. 4.5.2.5 <Method> Tag Der Element <Method> hat folgende Attribute: name ist der Methode-Name return legt den Rückgabewert der Methode fest. Dieser kann neben den Standardtypen wie String, int, lont, boolean etc. auch ein Array des Interface der aufrufenden Klasse sein, z.B. %interfacedata%[] (TLGen ersetzt den Platzhalter automatisch). manager ist der Manager Bean - Name client ist der Client Name (nur für die Test-Klassen) über welchen diese Methode aufgerufen werden kann. TLGen 127 StarData Gmb V 2.8 typerwd ist für den Datenbankzugriff-Typ (nur für die Test-Klassen). Dieses Attribut kann folgende Werte haben: 0 für die Abspeicherung eines Objekts in der Datenbank, 1 für das Lesen, 2 für das Ändern und 3 für das Löschen. methodtype ist eine Zahl und gibt dem Generator Informationen über Methode-Type. Folgende Typen sind erlaubt: o METHOD_TYPE_ERROR = -1; method build is not possible o METHOD_TYPE_FREE = 0; free methods, SQL free methods o METHOD_TYPE_COLUMN = 1; methods generate from columns o METHOD_TYPE_RELATION = 2; methods generate from relation o METHOD_TYPE_CLASS = 3; from configuration file (user method) o METHOD_TYPE_STANDARD = 4; standard method o METHOD_TYPE_SQL_STANDARD = 5; Query SQL-EJB Format (Default, from configdefault XML, Methods createQuery) o METHOD_TYPE_SQL_EJB = 6; Query SQL-EJB Format (from config XML file, Method createQuery()) o METHOD_TYPE_SQL_NAMED = 7; Query SQL-Named (Method createNamedQuery(), EJB named query type) o METHOD_TYPE_SQL_NATIVE = 8; Query SQL-Native (Method createNativeQuery(), EJB native query type) o METHOD_TYPE_SQL_OBJECT = 9; Query SQL method over "QuereyObject" for (Method create query) o METHOD_TYPE_SQL_NATIVE = 10; Query SQL method over "QuereyObject" for (Method create Native Query) o METHOD_SQL_CRITERIA = 11; SQL Criteria generate o METHOD_TYPE_SQL_MAPPINGS = 12; annotations for SQL Mapping in Entity Beans o METHOD_TYPE_PRIMKEY = 13; method for primary key o METHOD_TYPE_CONSTRUCTOR = 14; method for class constructor o METHOD_TYPE_HELPER = 15; helper method o METHOD_TYPE_FACTORY = 16; factory method o METHOD_TYPE_SET_DATA= 17; method for set data object o METHOD_TYPE_SQL_VIEW = 18; Query SQL view Bemerkung: Soll eine Methode Callback-Klassen übernehmen, dann sollte in der Seasion Bean MethodeType = 0 sein 4.5.2.6 <Variable> Tag Das Element <Variable>. hat folgende Attribute: name, Name des Elements vartype definiert den Field-Typ TLGen 128 StarData Gmb V 2.8 content = Ein „Platzhalter“, welcher durch den Generator mit den notwendigen Informationen ersetzt wird. fieldtype, mögliche Werte 0,1 oder 2. 0= Field wird in eine Klasse generiert, 1 in dessen Interface und 2 in beide. 0 ist Standard-Wert. abstract = true oder false (true ist der Standard-Wert) ist nur intern für den Generator. Falls Field-Content eine Klasse ist, wird der Klassen-Pfad im import-Bereich der Klasse hinein generiert. TLGen 129 StarData Gmb V 2.8 5 Verwendung von TLGen bei Softwarentwicklung (Bedingungsanleitung) und das Beispiel „Demo“-Beschreibung Die Verwendung von TLGen, Code-Generator, für die IT-Projektentwicklung basiert auf die RUP (Rational Unified Process)-Vorgehensweise für Softwareentwicklung. Als Technische Unterstützung wird empfohlen, das UML (Unified Modeling Language) als Modellierungsprache zu verwenden. TLGen, wie schon in Kap. 1 und 2 erwähnt, kann für eine vorhandene Datenbank (geeignet für Legacy Projekten) oder für ein komplett neues IT Projekt verwendet werden. Bei neuen Projekten ist Folgendes zu beachten: 1. Auf Grund von Fachdaten wird ein Domain-Modell mit Hilfe von UML entwickelt. Wichtig im DM ist, dass die Klassen „persistent“ als persistent gekennzeichnet werden, wobei alle anderen Klassen als „transient“. TLGen generiert ein SQL Skript (und die dazugehörige Datenbank) nur für die Persistenten Klassen als Tabellen (siehe Kap. 3.9). Dieses Domain-Model wird als XMI Datei gespeichert und ist für TLGen wichtige Grundlage für die Generierung (siehe Kap. 5.1). 2. Entwicklung von Konfigurationsdateien (siehe Kap. 4). Kann die Konfigurationsdateien mit den notwendigen Anpassungen, projektabhängig, verwenden. In Demo Beispiel sind Konfiguratiosdateien für die Verwendung einer „Oracle“- und einer „MySql“-Datenbank: a. für „Oracle“, „config_tlgen_demo.xml-Oracle” und “config_tlgen_demo_default.xml-Oracle“ b. für „MySql“, „config_tlgen_demo.xml-MySql“ und „config_tlgen_demo_default.xml-MySql“ 3. Entwicklung eines „ant“ „build“ Skripts. Auch in diesem Fall kann das „ant“ Skript von dem Beispiel als Grundlage verwendet und angepasst werden. 4. Generierung von Java Code. 5. Kodierung von Fachlogik in den von TLGen „callback“ generierten Klassen. 6. Projekt-Teste mit Hilfe von generierten JUnit Test Klassen. 7. Wiederholung der Punkte 1 bis 6, um ein optimales Projekt zu schaffen. Für ein Lagacy Projekt gilt die gleiche zuvor genannte Vorgehensweise ausser Punkt 1 und die Konfigurationsdateien müssen mehrere Informationen beinhalten (Beispiel vom Kap. 5.2). TLGen-Verwendung in einem neuen IT Projekt, „Demo“ Beispiel 5.1 Das „Demo“ Beispiel basiert auf das Domain Modell, dargestelt in Abbildung 4. Für die Generierung sind folgende Dateien notwendig: TLGen config. config_tlgen_demo_default.xml und config. config_tlgen_demo.xml, sind die Konfigurationsdateien build.build.xml, build.build_generator und build.properties, sind die “ant” Dateien doc.model.DomainModel01.xml, ist die UML Domain Modell-Datei. In unserem Beispiel verwenden wir für die Erzeugung dieser Datei den „EnterpriseArchitekt“ Tool von der Firma „Sparks Systems“. 130 StarData Gmb V 2.8 TLGen und fremde Jars (siehe Kap. 6.1) Die Generierung wird mit folgendem Befehl im Folder „build“ gestartet. …\build\ant In diesem Beispiel werden alle notwendigen Klassen generiert und einige (die Fachlogik im Beispiel) per Hand angepasst. Folgende Folder beinhalten nur generierte Klassen, die bei jeder Generierung neu erstellt werden: source.generated, in diesem Folder werden die Daten-, Json Daten- und MappingKlassen zwischen Daten und Json-Klassen, Session Beans mit eigenen Interfaces, Entity Beans und Entity Manager-Klassen generiert. All diese generierten Klassen darf man nicht mit einem Editor ändern und sind komplett funktionsfähig. source.help, hier befinden sich die JUnit generiertenTest Klassen source.interceptor, da werden die „Interceptor“ Klassen generiert, welche die runing Zeit messen Im Folder „common“ sind einige„super“ Klassen, notwendig für EJB 3. Diese Klassen sind nur ein Vorschlag für die „Demo“ und können geändert werden, wobei dies nicht notwendig ist, weil sie in allen IT Projekten gleich sein können. Folgende Folder beinhalten veränderbare Dateien und jede kann eine eigene Fachlogik bauen: source.criteria, beinhaltet die Dateien für den Kriteria Java Code. Im „Demo“ Beispiel sind nur die Klassen von „eu.stardata.demo.server.criteria.user.UserCriteria“ mit funktionalem Code. source.test, hier befinden sich die per Hand angepassten Klassen der generierten JUnit Test-Klassen aus dem Folder „source.help“ source.rest, da ist ein Beispiel für die Verwendung von „REST“ call’s, zwei Dateien, „eu.stardata.demo.server.rest.CallBackRest“ und „eu.stardata.demo.server.rest.CallBackRestBean“ sourde.soap, hier ein Beispiel für die Verwendung von „Web Service“ Technik Das „Demo“ Beispiel benötigt noch folgende Folder: result, beinhaltet die von „ant“ generierte „jars“, „wars“ „XML“ und „ears“ Dateien. resource, hier sind einige Hilfsdateien. lib, hier die für die Generierung notwendigen „jar“ Dateien log, hier werden die „log“ Dateien gespeichert. Folgendes ist für die Verwendung des„Demo“ Beispiels notwendig 1. 2. 3. 4. TLGen Entpackung der „demo.zip“ Datei Starten des Projekts „Project-Demo“ in ein Elipse Tool Eventuelle Änderungen von „paths“ in der Datei „build.properties“ Datenbank-Vorbereitung: o Einrichten eines Users mit dessen Zugriffsrechte 131 StarData Gmb V 2.8 Erstellung eines oder besser zweier „Tablespaces“ und Eintragung der Namen in die Konfigurationsdatei beim Tag <Generator>, Attributen „indexTablespace“ und „dataTablespace“ o Anpassen des Attributs „databaseConnect“ an den richtigen Werten in der Konfigurationsdatei Starten einer „Oracle“ v-11 Datenbank oder einer anderer Datenbank (falls eine andere Datenbank verwendet werden soll) im Tag <Generator>, Attribut „databaseConect“ den Inhalt, z.B. für MySql Datenbank ist dort einzutragen: „jdbc:mysql://localhost:3306/demo?characterEncoding=UTF8&amp;characterSetResults=UTF8&amp;autoReconnect=true&amp;zeroDateTimeBehavior=convertToNull“) Starten des „ant“ build. Dieser generiert die „SQL“ Skripts, Java Klasse, erstellt eine neue Datenbank (so lange im Attribut <Generator… makeDatenbase=true..> ist), generiert eine „ear“ Datei mit dessen Dateien und kopiert diese auf den Application Server Starten des Application Servers „JBoss-7.1.1“ Von Eclipse starten der Test call’s für die Abspeicherung und das Datenlesen in der Datenbank in folgender Reihenfolge: o Vom „useRole“ die Test Klasse „eu.stardata.test.user.RoleWriteRead“ starten und in der Datenbank die User Rollen abspeichern. In Eclipse bei „console“ sollten folgende Ausgaben erscheinen: o 5. 6. 7. 8. New primary key is = 4 RoleName :SuperAdmin Ejb3Optlock :0 UserRoleID :1 Description :Description from role :SuperAdmin ModifyDate :2013-02-13 11:36:30.002 RoleName :Admin Ejb3Optlock :0 UserRoleID :2 Description :Description from role :Admin ModifyDate :2013-02-13 11:36:30.425 RoleName :System Ejb3Optlock :0 UserRoleID :3 Description :Description from role :System ModifyDate :2013-02-13 11:36:30.446 RoleName :User Ejb3Optlock :0 UserRoleID :4 Description :Description from role :User ModifyDate :2013-02-13 11:36:30.46 o und von „user“ test Klasse „eu.stardata.test.user.UserWriteRead“: New primary key is = 1 UserID :1 Ejb3Optlock :0 Email :[email protected] PassWord :789 FirstName :Georg UserName :yyy-01 LastName :Fisher TLGen 132 StarData Gmb V 2.8 ModifyDate :2013-02-13 11:45:06.001 RoleName :System Ejb3Optlock :0 UserRoleID :3 Description :Description from role :System ModifyDate :2013-02-13 11:36:30.446 o Wenn drei oder mehrere „users“ gespeichert sind, kann die „REST“ Test Klasse „eu.stardata.test.rest.TestRestUser“ aufgerufen werden. Auf den Application Server erscheint folgende Anzeige: 11:56:04,669 INFO 11:56:04,733 INFO 11:56:04,735 INFO 11:56:04,791 INFO 11:56:04,793 INFO 11:56:04,837 INFO 11:56:04,839 INFO 11:56:04,878 INFO [stdout] (http--127.0.0.1-8080-1) ------- createUser -------[stdout] (http--127.0.0.1-8080-1) ------- fetchUser -------[stdout] (http--127.0.0.1-8080-1) Name :yyy-01 [stdout] (http--127.0.0.1-8080-1) ------- countUsers -------[stdout] (http--127.0.0.1-8080-1) Name :xxx-01 [stdout] (http--127.0.0.1-8080-1) ------- deleteUser -------[stdout] (http--127.0.0.1-8080-1) userId :4 [stdout] (http--127.0.0.1-8080-1) ------- updateUser -------- und auf der Eclispe „console“ folgendes (Die Daten für Users können unterschiedlich sein, abhängig vom Abgespeicherten): ----------- testcreateUser() ----------strResponse :{"ejb3Optlock":0,"email":"[email protected]","passWord":"xyz","firstName":"Cris","userID":4,"userName":"us er03","lastName":"Smith","modifyDate":null,"product":null,"userRole":[{"roleName":null,"ejb3Optlock":0,"userRoleID":2 ,"description":null,"modifyDate":null,"user":null}]} Ejb3Optlock :0 Email :[email protected] PassWord :xyz FirstName :Cris UserID :4 UserName :user03 LastName :Smith ModifyDate :null RoleName :null Ejb3Optlock :0 UserRoleID :2 Description :null ModifyDate :null ----------- testfetchUser() ----------Response :{"requestParameters":{},"totalResultSize":0,"result":[{"ejb3Optlock":0,"email":"[email protected]","passWo rd":"789","firstName":"Georg","userID":1,"userName":"yyy01","lastName":"Fisher","modifyDate":null,"product":null,"userRole":[{"roleName":"System","ejb3Optlock":0,"userRoleI D":3,"description":"Description from role :System","modifyDate":1360751790446,"user":null}]},{"ejb3Optlock":0,"email":"[email protected]","pass Word":"123","firstName":"John","userID":2,"userName":"yyy01","lastName":"Johnson","modifyDate":null,"product":null,"userRole":[{"roleName":"System","ejb3Optlock":0,"userRo leID":3,"description":"Description from role :System","modifyDate":1360751790446,"user":null}]}]} ----------- testcountUsers() ----------strResponse :1 ----------- testdeleteUser() ----------strResponse :OK ----------- testupdateUser() ----------strResponse :{"ejb3Optlock":0,"email":"[email protected]","passWord":"xyzabc","firstName":"John","userID":3,"userName":"userupdate","lastName":"Johnson","modifyDate":1360756564866,"product":null,"userRole":[{"roleName":null,"ejb3Optlock ":0,"userRoleID":2,"description":null,"modifyDate":null,"user":null}]} o TLGen Es kann auch die Test-Klasse „eu.stardata.test.soap.TestSoapUser“ für Web Service aufgerufen werden. Auf den Application Server sollte folgende Anzeige erscheinen: 133 StarData Gmb V 2.8 13:29:17,775 INFO [stdout] (http--127.0.0.1-8080-2) ------- retrieveUser -------13:29:17,777 INFO [stdout] (http--127.0.0.1-8080-2) Name :yyy-01 13:29:18,233 INFO [stdout] (http--127.0.0.1-8080-2) ------- updateUser -------- Und auf der Eclispe „console“ folgendes: ------------ Response Retrive User ----------------Ejb3Optlock :1 Email :[email protected] PassWord :xyz$abc FirstName :Stefan UserID :1 UserName :yyy-01 LastName :Stefanson ModifyDate :Wed Feb 13 13:23:02 CET 2013 RoleName :Admin Ejb3Optlock :0 UserRoleID :2 Description :Description from role :Admin ModifyDate :Wed Feb 13 12:38:04 CET 2013 Ejb3Optlock :0 Email :[email protected] PassWord :789 FirstName :John UserID :3 UserName :yyy-01 LastName :Johnson ModifyDate :Wed Feb 13 12:42:11 CET 2013 RoleName :SuperAdmin Ejb3Optlock :0 UserRoleID :1 Description :Description from role :SuperAdmin ModifyDate :Wed Feb 13 12:38:03 CET 2013 ----------- Send Update User ---------------------- Response Update User ----------------Ejb3Optlock :0 Email :[email protected] PassWord :xyz$abc FirstName :Stefan UserID :2 UserName :test LastName :Stefanson ModifyDate :Wed Feb 13 13:29:18 CET 2013 RoleName :null Ejb3Optlock :0 UserRoleID :2 Description :null ModifyDate :null Bei Verwendung von ein JBoss v.7.1.1 sollten folgende Eintragungen in der Datei „standalone.xml“, abhängig von der verwendeten Datenbank, erfolgen: für „Oracle“ Datenbank: …………………. <datasource jta="true" jndi-name="java:/vmsPool" pool-name="vmsPool" enabled="true" use-java-context="true" use-ccm="true"> <connection-url>jdbc:oracle:thin:@localhost:1521:SDW6ORCL</connection-url> <driver>oracle</driver> <security> <user-name>vms</user-name> <password>vms</password> </security> </datasource> TLGen 134 StarData Gmb V 2.8 …………………………. <drivers> <driver name="oracle" module="oracle.jdbc"> <driver-class>oracle.jdbc.OracleDriver</driver-class> </driver> ………………………… und für “MySql”: ……………………….. <datasource jta="true" jndi-name="java:/demoPool" pool-name="demoPool" enabled="true" use-java-context="true" use-ccm="true"> <connection-url>jdbc:mysql://localhost:3306/demo?characterEncoding=UTF8&amp;characterSetResults=UTF8&amp;autoReconnect=true&amp;zeroDateTimeBehavior=convertToNull</connection-url> <driver>mysql</driver> <transaction-isolation>TRANSACTION_REPEATABLE_READ</transaction-isolation> <pool> <min-pool-size>10</min-pool-size> <max-pool-size>250</max-pool-size> <prefill>true</prefill> <use-strict-min>false</use-strict-min> <flush-strategy>FailingConnectionOnly</flush-strategy> </pool> <security> <user-name>demo</user-name> <password>demo</password> </security> <validation> <check-valid-connection-sql>SELECT 1</check-valid-connection-sql> </validation> <timeout> <blocking-timeout-millis>30000</blocking-timeout-millis> <idle-timeout-minutes>5</idle-timeout-minutes> </timeout> <statement> <prepared-statement-cache-size>200</prepared-statement-cache-size> <share-prepared-statements>true</share-prepared-statements> </statement> </datasource> ………………………… <drivers> <driver name="oracle" module="oracle.jdbc"> <driver-class>oracle.jdbc.OracleDriver</driver-class> </driver> …………………………… Bemerkung: Wir empfehlen eine Übung mit dem Einbau eigener Klassen, mit Verwendung der restlich generierten Klassen „product“, „production“ und dann die Erweiterung des Domain-Modells mit eigenen Klassen durchzuführen. 5.2 Verwendung von TLGen in ein Legacy IT Projekt, „Legacy“ - Beispiel Das „Legacy“-Beispiel basiert auf das Daten-Modell aus Abbildung 5. Dieses Beispiel kann von www.tlgen.com heruntergeladen werden. Die Beschreibung für dieses TLGen Beispiel befindet sich in der „Readme.txt“ Datei. TLGen 135 StarData Gmb V 2.8 6 TLGen Installation TLGen wird als eine JAR Datei geliefert. Zu deren Verwendung gibt es keine Besonderheiten. In source/common sind ein paar Klassen (Super-, Exception- oder Client Remote-Service-Klassen), die TLGen als Standard Klassen in der Generierung verwendet. Diese können erweitert oder geändert werden und sind optional. Der TLGen Generierungsvorgang kann über Apache ANT verwendet werden, da TLGen einen eigenen Tag „tlgen“ besitzt (siehe Listing 92) <target name="generator" depends="generator-init" description="--> generate helper file"> <tlgen configFile = "${output}/config/config_tlgen_demo.xml" configStandardFile = "${output}/config/config_tlgen_demo_default.xml" databaseConnect = "jdbc:oracle:thin:@localhost:1521:ORCL" databaseDriver = "oracle.jdbc.driver.OracleDriver" userPwd = "Demo/demo" database = "Oracle" logFile = "${output}/log/generator_demo.log" logTest = "${output}/log/test_demo.log" logEntity = "${output}/log/entity_demo.log" pathToGenerate = "${output}/source/generated" debugValue = "debug" classpathref = "tlgen.class.path" > <fileset dir="${src.server}"> <include name="**/${subsystem.dir}/**/*SessionBean.java"/> </fileset> </tlgen> </target> Listing 92: Verwendung von <tlgen> Tag Der Tag „generator“ benötigt folgende Attribute: configFile ist die Konfigurationsdatei mit deren Adresse configStandardFile ist die Standard Konfigurationsdatei mit deren Adresse databaseConnec, ist der Connect String für eine Datenbank databaseDriver ist der Datenbank-Treiber userPwd ist der User und dessen Passwort für die Access zur Datenbank database ist die Datenbank (z. B „Oracle“) logFile Datei-Name für den Platz, wo alle Informationen über die Generierung geschrieben werden sollten logTest für die generierten Test-Klassen logEntity für die generierten Entity-Klassen, logManager für die generierten Manager-Klassen logSession, für die generierten Session Bean-Klassen pathToGenerate ist die Adresse, wo der generierte Code gespeichert werden sollte TLGen 136 StarData Gmb V 2.8 debugValue ist „debug“, hier werden die Debug Prints auf der Konsole geschrieben classpathref ist die Adresse, wo sich die benötigten JARS befinden (siehe Liste von 6.1) Eine komplette ANT Datei ist im TLGen Example Paket ersichtlich. 6.1 Verwendete Tools und Externe Programme Liste von verwendeten TLGen JAR’s für die Generierung (siehe auch das Code Beispiel): „Tlgen28.jar“, beinhaltet den TLGen Generator „base.jar“, beinhaltet einige Helper methods „common.jar“, „super“ Klassen, die von jeden Benutzer gändert werden (sind geliefert auch in Java Code) können und fremde JAR’s: für den Application-Server „JBoss v.7“: o „jboss-annotations-api_1.1_spec-1.0.0.Final.jar“ o “jboss-client.jar” o “cdi-api-1.0-SP4.jar” o “hibernate-core-4.0.1.Final.jar”, o “hibernate-jpa-2.0-api-1.0.1.Final.jar” o “javax.inject-1.jar” o “jboss-ejb-api_3.1_spec-1.0.1.Final.jar” o “jboss-interceptors-api_1.1_spec-1.0.0.Final.jar” o “jboss-jaxrs-api_1.1_spec-1.0.0.Final.jar” Für Verwendung von „Oracle“ Datenbank (von der Firma Oracle) Version 11: o „ojdbc6_g.jar“ oder „ojdbc6.jar“ Für Vervendung von „MySQL“ Datenbank (von der Firma Oracle:) o „mysql-connector-java-5.1.6-bin.jar“ Für REST call’s: o „async-http-servlet-3.0-2.3.2.Final.jar“ o „async-http-servlet-3.0-2.3.2.Final-jandex.jar“ o „gson-2.2.2.jar“ o „jackson-core-asl-1.9.2.jar“ o „jackson-jaxrs-1.9.2.jar“ o „jackson-mapper-asl-1.9.2.jar“ o „resteasy-jaxrs-2.3.2.Final.jar“ o „resteasy-jaxrs-2.3.2.Final-jandex.jar“ „ant.jar“ für Generierung mit Hilfe von „ant“ „junit-4.5.jar“ für Test Klassen TLGen 137 StarData Gmb V 2.8 Bemerkung: Andere jars, z.B. Datenbank-Verbindung oder Application Server Client/Server sind von der Datenbank bzw vom Application Server, der verwendet wird, abhängig. 6.2 Verwendung von „ant“ für die Generierung von Java Code Für die Verwendung von „ant“ für die Code Generierung besitzt TLGen einen eigenen Taget „generator“ (Sihe Kap. 5.1, und 5.2). Der Target „generator“ hat folgende Attribute (siehe Table 12: Attribute- für den „ant“ <target> „genertor“): Table 12: Attribute- für den „ant“ <target> „genertor“ Attribut Value configFile Mandatory Kommentar yes Konfigurationsdatei-Name encoding „Cp1252“ no „Cp1252“ ist Default-Wert für die Generierung von SQL Skripts logFile Datei Name no Generator main Log-Datei logTest Datei Name no Log-Datei für die Generierung von Test-Klassen logEntity Datei Name no Log-Datei für die Generierung von Entity BeansKlassen debugValue debug no TLGen läuft in Debug Modus classpathref classpath no relativePath true no Default ist „true“ und verwendet für die Generierung relative Paths, bei „false“ werden die absolute Paths verwendet logManager Datei Name no Log-Datei für die Generierung von Manager Entity Beans-Klassen logSession Datei Name no Log-Datei für die Generierung von Session BeansKlassen logClassIf Datei Name no Log-Datei für die Generierung von Daten- und JSonKlassen 6.3 Verwendung von „Maven“ für die Generierung von Java Code Für die Verwendung von „Maven“ innerhalb eines Java Projekts ist in der Code Generierung mit TLGen folgende Eintragung notwendig „pom.xms“ (siehe Listing 93). Dieses Beispiel basiert auf dieVerwendung von TLGen „ant“ Tergent <generator> (siehe auch 6.2). TLGen 138 StarData Gmb V 2.8 <build> <resources> <resource> <directory>src/main/tlgen/config</directory> <filtering>true</filtering> </resource> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> <id>filter-binding</id> <phase>process-resources</phase> <configuration> <failOnError>true</failOnError> <target> <taskdef name="tlgen" classname="eu.stardata.tlgen.ant.TlgAntTask" classpathref="maven.plugin.classpath" /> <tlgen configFile="${project.build.directory}/classes/config_tlgen_vms.xml" configStandardFile="${project.build.directory}/classes/config_tlgen_vms_default.xml" databaseConnect="${testdb.url}" databaseDriver="oracle.jdbc.OracleDriver" userPwd="${testdb.user}/${testdb.password}" database="" logFile="${project.build.directory}/generator_vms.log" logTest="${project.build.directory}/test_vms.log" logEntity="${project.build.directory}/entity_vms.log" pathToGenerate="${project.build.directory}/generated-sources/tlgen"> </tlgen> </target> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> </plugin> …………………………………… Listing 93: Maven „pon.xml“ Datei Folgende Eintragungen sind in “pom.xml” durchzuführen: <directory>src/main/config<directory>, Bei dieser Adresse sind beide Konfigurationsdateien vorhanden <taskdef name="tlgen" classname="eu.stardata.tlgen.ant.TlgAntTask", TLGen Generator Aufruf Definierung von Variablen: o ${project.build.directory}, Build Folder Adresse o "${testdb.url}", für Database Connect o "${testdb.user}/${testdb.password}", Database-Zugriffsrechte Alle drei „jar“ Dateien, “tlgen.jar”, „base.jar“ und „common.jar“, welcheTLGen Generator benötigt, sollten mit Hilfe eines Repository imProjekt eingebunden werden. TLGen 139 StarData Gmb V 2.8 7 Beispiele von generiertem Code Es folgen Beispiele für den generierten Code aus dem „Demo“-Beispiel. 7.1 Standard Konfigurationsdatei <?xml version="1.0" encoding="UTF-8"?> <!-- ======================================================================= --> <!-config standard file for Project-Demo --> <!-- ********************************************************************* --> <!-Titus Livius Rosu, Titus Rosu, StarData GmbH --> <!-2013/01/18 --> <!-- ======================================================================= --> <Standard name="Standard-Demo" company="StarData GmbH" path="eu.stardata.%project%" commentary="**** do not change with a file editor *****" > <Project testRelation="false,true,false,false"/> <!--Locator name="eu.stardata.server.common.ejb.ServiceLocator" instance="getInstance" local="getLocalReference" remote="getRemoteReference"> </Locator--> <Class path="eu.stardata.demo.business" name="eu.stardata.%project%.business.%package%.%classname%Data|eu.stardata.%project%.business.%package%.%classname%DataIf" classType="Class"> <!--pathEnum="eu.stardata.%project%.business.enums.%package%.%classname%" pathType="eu.stardata.%project%.business.types.%package%.%classname%"--> <Implements name="java.io.Serializable"/> <!--Extends name="com.tlgen.common.data.BaseData"/--> <!--Extends name="com.tlgen.common.data.BaseDataIf" type="interface"/--> </Class> <Entity path="eu.stardata.%project%.server.persistence" name="eu.stardata.%project%.server.persistence.%package%.entity.%classname%Entity" seqstrategy="SEQUENCE" classType="Entity"> <Implements name="java.io.Serializable" type="interface"/> <!--Extends name="com.tlgen.common.ejb.entity.BaseEntityBean"/--> <!--Annotation name="javax.persistence.Entity"/> <Annotation name="javax.persistence.Table"/> <Annotation name="javax.persistence.SequenceGenerator"/--> <Annotation name="org.hibernate.annotations.GenericGenerator" replacement="javax.persistence.SequenceGenerator"/> </Entity> <Mapping name="eu.stardata.%project%.business.%package%.%classname%Map" classType="Mapping"> </Mapping> <Criteria name="eu.stardata.%project%.server.criteria.%package%.%classname%Criteria" classType="Criteria"> </Criteria> <JSon name="eu.stardata.%project%.business.%package%.%classname%JSon" classType="JSon"> </JSon> <Manager name="eu.stardata.%project%.server.persistence.%package%.manager.%classname%Manager" classType="Manager" transactiontype="JTA" container="false" exception="com.tlgen.common.exception.PersistenceException"> <!--Extends name="com.tlgen.common.ejb.manager.BaseManager"/--> <Implements name="eu.stardata.%project%.server.persistence.%package%.managerif.%classname%ManagerIf"/> <!--Annotation name="javax.ejb.Stateless"/> <Annotation name="javax.ejb.Local"/--> <!--Variable name="JNDI_NAME" vartype="string" content="%interfacemanager%" fieldtype="1" abstract="true"/> <Variable name="EAR_NAME" vartype="string" content="%earname%" fieldtype="1" abstract="true"/> <Variable name="m_manager" vartype="javax.persistence.EntityManager"> <Annotation name="javax.persistence.PersistenceContext"> <Parameter name="properties" type="Text-Prop"/> <Parameter name="unitName" type="%clientdata%.MANAGER_NAME"/> </Annotation> </Variable--> <!--Method name="getManager" return="%interfacemanager%" methodtype="4"> TLGen 140 StarData Gmb V 2.8 <Exception name="com.tlgen.common.exception.PersistenceException"/> </Method> <Method name="create" return="%interfacedata%" methodtype="4"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter type="%interfacedata%" /> </Method> <Method name="update" methodtype="4" return="void"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter type="%interfacedata%" /> </Method> <Method name="remove" methodtype="4" return="void"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter type="%interfacedata%" /> </Method> <Method name="flush" methodtype="4" return="void"> <Exception name="com.tlgen.common.exception.PersistenceException"/> </Method> <Method name="close" methodtype="4" return="void"> <Exception name="com.tlgen.common.exception.PersistenceException"/> </Method> <Method name="clear" methodtype="4" return="void"> <Exception name="com.tlgen.common.exception.PersistenceException"/> </Method> <Method name="findByPrimaryKey" return="%interfacedata%" methodtype="5"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter type="%interfacedata%" /> </Method> <Method name="findAll" return="%interfacedata%[]" methodtype="5"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Sql name="SQL_FIND_ALL" sql="select o from %classname%Entity o" /> </Method> <Method name="getEntityByPrimaryKey" return="%classentity%" methodtype="5"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter type="%interfacedata%" /> </Method--> </Manager> <Session name="eu.stardata.%project%.server.persistence.%package%.%classname%SessionBean" classType="Session" managername="manager%classname%" transactiontype="JTA"> <!--Extends name="com.tlgen.common.ejb.session.BaseSessionBean"/--> <!--Annotation name="javax.annotation.security.RolesAllowed"> <Parameter name="ADMIN"/> </Annotation--> <!--Annotation name="javax.ejb.Stateless"/> <Annotation name="javax.ejb.Remote"/--> <Client name="eu.stardata.%project%.client.bci.%package%.%classname%Bci" type="public" exception = "com.tlgen.common.exception.PersistenceException"> <!--Extends name="eu.stardata.server.common.bci.BciFactory"/--> <!--Annotation name="javax.ejb.Remote"/--> <!--Variable type="public final static" vartype="string" name="MANAGER_NAME" content="%sessionmanagername%" fieldtype="1" abstract="true"/> <Variable type="public final static" vartype="string" name="EAR_NAME" content="%earname%" fieldtype="1" abstract="true"/> <Variable type="public final static" vartype="string" name="JNDI_NAME" content="%interfacemanager%" fieldtype="1" abstract="true"/--> </Client> <Interceptor name="eu.stardata.%project%.server.persistence.%package%.TimeCore" path ="C:/Projects/ProjectDemo/source/generated" merge="1"> <Method name="timeTrace" return="java.lang.Object" finally="C:/Projects/Project-Demo/resources/FinallyTime.xml"> <!--Annotation name="javax.interceptor.AroundInvoke"/--> <!--Parameter type="javax.interceptor.InvocationContext" name="invocation"/--> <!--Exception name="com.tlgen.common.exception.PersistenceException"/--> </Method> </Interceptor> <Xml-persistence type="persistence"> <Property name="show_sql" type="true" /> </Xml-persistence> </Session> <Message name="eu.stardata.%project%.server.persistence.%package%.message" classType="Message" > </Message> <UmlControl name="DomainModel" lenString="255" versionDb="EJB3_OPTLOCK" versionDbType="NUMBER(12,0)" enumType="VARCHAR2(32)" primKeyType="long" endPrimKey="_ID" TLGen 141 StarData Gmb V 2.8 endSequence="_1SQ" sequenceType="1" sequenceCache="10" sequenceInit="1" sequenceIncrement="1" dataTablespace="ADMDATA" indexTablespace="ADMINDEX"> <Column name="EJB3_OPTLOCK" type="long" dbType="NUMBER" dataLen="16" locking="true"/> <Column name="MODIFY_DATE" type="Date" dbType="TIMESTAMP" dataLen="6" locking="false" nullable="true" defaultValue="SYSDATE"/> <!--Column name="DB_VERSION" type="long" dbType="NUMBER" dataLen="16" locking="true"/--> <!--Column name="ID" type="String" dbType="VARCHAR2" dataLen="255" unique="true"/--> <!--ColType name="char" type="CHAR"/> <ColType name="Date" type="TIMESTAMP(6)"/> <ColType name="String" type="VARCHAR2"/> <ColType name="DbType" type="NUMBER(10,0)"/> <ColType name="byte[]" type="BLOB"/> <ColType name="int" type="NUMBER(12,0)"/> <ColType name="Integer" type="NUMBER(12,0)"/> <ColType name="long" type="NUMBER(24,0)"/> <ColType name="Long" type="NUMBER(24,0)"/> <ColType name="double" type="NUMBER(28,4)"/> <ColType name="Double" type="NUMBER(28,4)"/> <ColType name="float" type="NUMBER(12,2)"/> <ColType name="Float" type="NUMBER(12,2)"/> <ColType name="short" type="SMALLINT"/> <ColType name="Short" type="SMALLINT"/> <ColType name="boolean" type="NUMBER(1,0)"/> <ColType name="Boolean" type="NUMBER(1,0)"/--> <NameChange name="Order" type="OrderTable"/> <NameChange name="User" type="UserTable"/> <!-################################################## --> <!-Settings for Relation --> <!-################################################## --> <Relation type="recursiv" name="recursiv" value="true"/> <!-if no linkname is assigned --> <!--Relation type="recursiv" name="recursivName" value="Parent"/> <Relation type="sameRelationDirection" name="sameRelationDirection" value="true"/--> <!-if no linkname is assigned --> <!--Relation type="sameRelationDirection" name="sameRelationDirectionName" value="Parent"/> <Relation type="backRelationDirection" name="backRelationDirection" value="true"/> <Relation type="backRelationDirection" name="backRelationDirectionAdd" value="true"/--> <!-if no linkname is assigned --> <!--Relation type="backRelationDirection" name="backRelationDirectionName" value=""/--> <!-- #### --> <!-- ALGO --> <!-- #### --> <!-- Relation: "<#>=====" | Direction: "Source -> Destination" | Navigation: "<= to Source" --> <!--Association type="Composition" name="Composition:Source -> Destination|toSource" position="Source" navigable="Source" optional="false" nullable ="false" /--> <!-- Relation: "<#>====>" | Direction: "Source -> Destination" | Navigation: "=> to Destination" --> <!--Association type="Composition" name="Composition:Source -> Destination|toTarget" position="Source" navigable="Target" optional="false" nullable ="true" insertable="true" updateable="true" cascade="PERSIST,MERGE,REMOVE" /--> > <!-- Relation: "< >=====" | Direction: "Source -> Destination" | Navigation: "<= to Source" --> <!--Association type="Shared" name="Shared:Source -> Destination|toSource" position="Source" navigable="Source" nullable ="true" /-- <!-- Relation: "< >====>" | Direction: "Source -> Destination" | Navigation: "=> to Destination" --> <!--Association type="Shared" name="Shared:Source -> Destination|toTarget" position="Source" navigable="Target" nullable ="true" insertable="true" updateable="true" cascade="PERSIST,MERGE" /--> <!-- Relation: "<#>====="" | Direction: "Destination -> Source" | Navigation: "<= to Destination" --> <!--Association type="Composition" name="Composition:Destination -> Source|toTarget" position="Target" navigable="Target" optional="false" nullable ="false" /--> <!-- Relation: "<#>====>" | Direction: "Destination -> Source" | Navigation: "=> to Source" --> <!--Association type="Composition" name="Composition:Destination -> Source|toSource" position="Target" navigable="Source" optional="false" nullable ="true" insertable="true" updateable="true" cascade="PERSIST,MERGE,REMOVE" /--> <!-- Relation: "< >=====" | Direction: "Destination -> Source" | Navigation: "<= to Destination" --> <!--Association type="Shared" name="Shared:Destination -> Source|toTarget" position="Target" navigable="Target" nullable ="true" /--> <!-- Relation: "< >====>" | Direction: "Destination -> Source" | Navigation: "=> to Source" --> <!--Association type="Shared" name="Shared:Destination -> Source|toSource" position="Target" navigable="Source" nullable ="true" insertable="true" updateable="true"/--> TLGen 142 StarData Gmb V 2.8 <!-- Changes "Destination -> Source" from ManyToOne in OneToMany and OneToMany in ManyToOne --> <!-If: "sourceNavigability == UML_CONNECTION_END_NAVIGABLE_TYPE.navigable OR direction == UML_CONNECTION_END_TYPE.DestinationToSource" --> <!--Relation type="ChangeDirection" name="0" value="true" /--> <!-If: "(targetAssociation == UML_ASSSOCIATION_TYPE.composition OR targetAssociation == UML_ASSSOCIATION_TYPE.shared) AND (sourceNavigability == UML_CONNECTION_END_NAVIGABLE_TYPE.navigable && direction == UML_CONNECTION_END_TYPE.DestinationToSource)" --> <!--Relation type="ChangeDirection" name="1" value="true" /--> <!-- Overwrites the results computed from the association tags above!!! --> <!--Association type="OneToOne" name="OneToOne" overwrite="true" direction="true" optional="true" insertable="true" updateable="true" /> <Association type="OneToMany" name="OneToMany" overwrite="true" direction="true" insertable="true" updateable="true" /> <Association type="ManyToOne" name="ManyToOne" overwrite="true" direction="true" optional="true" insertable="true" updateable="true" /> <Association type="ManyToMany" name="ManyToMany" overwrite="true" direction="true" optional="true" insertable="true" updateable="true" cascade="PERSIST,MERGE,REMOVE" /--> <!-################################################## <!-Property Values for the Relations - DO NOT CHANGE!!! --> <!-################################################## <!--RelationType name="mStandard" type="RELATION_TYPE" return="One" value="1"/> <RelationType name="mNull" type="RELATION_TYPE" return="One" value="null"/> <RelationType name="m0" type="RELATION_TYPE" return="One" value="0"/> <RelationType name="m1" type="RELATION_TYPE" return="One" value="1"/> <RelationType name="m0_1" type="RELATION_TYPE" return="One" value="0..1"/> <RelationType name="m0_n" type="RELATION_TYPE" return="Many" value="0..n"/> <RelationType name="m0_infinite" type="RELATION_TYPE" return="Many" value="0..*"/> <RelationType name="m0_infinite" type="RELATION_TYPE" return="Many" value="*"/> <RelationType name="m1_n" type="RELATION_TYPE" return="Many" value="1..n"/> <RelationType name="m1_infinite" type="RELATION_TYPE" return="Many" value="1..*"/> <RelationType name="mm_n" type="RELATION_TYPE" return="Many" value="m..n"/> --> --> <AggregationType name="None" type="UML_ASSSOCIATION_TYPE" return="association" value="none"/> <AggregationType name="Shared" type="UML_ASSSOCIATION_TYPE" return="shared" value="shared"/> <AggregationType name="Composition" type="UML_ASSSOCIATION_TYPE" return="composition" value="composite"/> Destination"/> Source"/> <DirectionType name="Unspecified" type="UML_CONNECTION_END_TYPE" return="unspecified" value="Unspecified"/> <DirectionType name="SourceToDest" type="UML_CONNECTION_END_TYPE" return="sourceToDestination" value="Source -> <DirectionType name="DestToSource" type="UML_CONNECTION_END_TYPE" return="DestinationToSource" value="Destination -> <DirectionType name="BiDirectional" type="UML_CONNECTION_END_TYPE" return="bidirectional" value="Bi-Directional"/> <AssociationType name="Association" type="UML_ASSSOCIATION_TYPE" return="association" value="Association"/> <AssociationType name="Aggregation" type="UML_ASSSOCIATION_TYPE" return="aggregation" value="Aggregation"/> <AssociationSubType name="Association" type="UML_ASSSOCIATION_TYPE" return="association" value="null"/> <AssociationSubType name="Strong" type="UML_ASSSOCIATION_TYPE" return="composition" value="Strong"/> <AssociationSubType name="Weak" type="UML_ASSSOCIATION_TYPE" return="shared" value="Weak"/> <Navigability name="None" type="UML_CONNECTION_END_NAVIGABLE_TYPE" return="none" value="None"/> <Navigability name="Navigable" type="UML_CONNECTION_END_NAVIGABLE_TYPE" return="navigable" value="Navigable"/> <Navigability name="NonNavigable" type="UML_CONNECTION_END_NAVIGABLE_TYPE" return="none" value="Non-Navigable"/> <Navigability name="Unspecified" type="UML_CONNECTION_END_NAVIGABLE_TYPE" return="unspecified" value="Unspecified"/> <Compare name="manytomany" type="RELATION_TYPE" return="ManyToMany" value="Many" /> <Compare name="manytomany" type="RELATION_TYPE" return="ManyToMany" value="Many" /> <Compare name="onetomany" type="RELATION_TYPE" return="OneToMany" value="One" /> <Compare name="onetomany" type="RELATION_TYPE" return="OneToMany" value="Many"/> <Compare name="manytoone" type="RELATION_TYPE" return="ManyToOne" value="Many" /> <Compare name="manytoone" type="RELATION_TYPE" return="ManyToOne" value="One"/> <Compare name="onetoone" type="RELATION_TYPE" return="OneToOne" value="One"/> <Compare name="onetoone" type="RELATION_TYPE" return="OneToOne" value="One"/--> </UmlControl> </Standard> TLGen 143 StarData Gmb V 2.8 7.2 Konfigurationsdatei <?xml version="1.0" encoding="UTF-8"?> <!-- ======================================================================= --> <!-config file for Project-Demo --> <!-- ********************************************************************* --> <!-Titus Livius Rosu, Titus Rosu, StarData GmbH --> <!-2013/01/18 --> <!-- ======================================================================= --> <!-- (JBoss) datasource = "java:/demoPool"; (Glasfish) datasource = "jdbc/demoPool"; (Weblogic) datasource = "demoPool" (Websphere)datasource = "jdbc/demoPool" datasource = "java:comp/env/jdbc/demoPool" databaseConnect="jdbc:oracle:thin:@localhost:1521:sdw6orcl" indexTablespace="CCPINDEX" dataTablespace="CCPDATA" --> <Generator name="demo" inputsource="database" datasource="java:/demoPool" appserver="JBoss7" location="C:/Projects/Project-Demo/project" standardConfigFile="C:/Projects/Project-Demo/config/config_tlgen_demo_default.xml" umlFile="C:/Projects/Project-Demo/doc/model/DomainModel01.xml" databaseConnect="jdbc:oracle:thin:@localhost:1521:sdw6orcl" database="ORACLE" userPwd="demo/demo" type="guml" mapping="true" databaseScript="C:/Projects/Project-Demo/doc/db/demo_schema.sql" makeDatabase="false" makeJavaCode="true" makeDatabaseDiff="false" indexTablespace="COINDEX" dataTablespace="CODATA" initProgram="eu.stardata.base.config.InitProgramm" keyName="eu.stardata.base.config.ConfigKeyNames" reference="true" > <!-- Glasfish --> <!-- Weblogic org.omg.CORBA.ORBInitialHost=localhost org.omg.CORBA.ORBInitialPort=3700 initialcontextfactory="java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory" java.naming.factory.url.pkgs=com.sun.enterprise.naming java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl initialcontext = "t3://localhost:7001" initialcontextfactory="weblogic.jndi.WLInitialContextFactory" initialcontextpkgprefix=" " --> <!-- JBoss initialcontext = "jnp://localhost:9099" initialcontext = "jnp://localhost:1099" initialcontextfactory="org.jnp.interfaces.NamingContextFactory" initialcontextpkgprefix="org.jboss.naming:org.jnp.interfaces" JBOSS6 JBOSS7 initialcontext = "jnp://localhost:1099" initialcontextfactory="org.jboss.iiop.naming.ORBInitialContextFactory" initialcontextpkgprefix="org.jboss.naming:org.jnp.interfaces" initialcontext = "remote://localhost:4447" initialcontextfactory = "org.jboss.naming.remote.client.InitialContextFactory.class.getName" contextkey = "jboss.naming.client.ejb.context" contextvalue = "true" optionskey = "jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT" optionvalue = "false" --> <!-- IBM Websphere TLGen 144 StarData Gmb V 2.8 initialcontext = "iiop://localhost:2809" initialcontextfactory="com.ibm.websphere.naming.WsnInitialContextFactory" initialcontextpkgprefix=" " --> <Project name="Project Demo for DomainModel" initialcontext = "remote://localhost:4447" initialcontextfactory = "org.jboss.naming.remote.client.InitialContextFactory.class.getName()" contextkey = "jboss.naming.client.ejb.context" contextvalue = "true" optionskey = "jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT" optionvalue = "false" managermethods="Order,ProductPrice,User,UserRole" type="guml" methods="public" sequencegen="SEQ_STORE" format="0" import="true" data="true" level="true" testRelation="true,true,true,true" persistence="false" persistenceUnit="true" multiReturnType="0" earname="demo" security="demo" enumsString="true" createTyp="0" restPort="8080" pathTest="C:/Projects/Project-Demo/source/help" pathCriteria="C:/Projects/Project-Demo/source/criteria" pathInterceptor="C:/Projects/Project-Demo/source/interceptor" criteria="true" mappedByOtM="true" foreignKeyIndex="true" jsonData="true" jsonLocking="true" > <!-- ================================================= --> <!-- Design von user Session --> <!-- ================================================= --> <Design name="user" > <Commentary name="This is a generate package for 'user'"/> <!-- init the Manager Classes --> <Manager> <Method name="findByName" parameter="java.lang.String" return="%interfacedata%[]" manager="User" methodtype="6"> <Parameter name="name" type="java.lang.String"/> <Sql sql="select o from UserEntity o where o.userName = :name" /> </Method> <Method name="findByLastName" manager="User" mapping="true" methodtype="8"> <Parameter name="name" type="java.lang.String"/> <Sql sql="SELECT * FROM User WHERE username = ? ORDER BY LastName" /> </Method> <Method name="countUserTyp9" return="java.util.List&#60;Object&#62;" manager="User" methodtype="9"> <Sql name="countUserTyp9" sql="select count(o) from UserEntity o" /> </Method> <Method name="demoUserFunction" return="java.util.List&#60;Object&#62;" manager="User" mapping="true" methodtype="10"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Sql sql="select rawtohex(sys_guid()) from dual" /> </Method> </Manager> <Manager criteria="true" merge="1"> <Method name="countUserTyp11" return="java.lang.Long" criteria="true" manager="User" methodtype="11"> <Parameter name="name" type="java.lang.String"/> </Method> </Manager> <!-- init the Session Classes --> <!--Session> </Session--> <!-- init the Test Classes --> <Test name="eu.stardata.demo.client.test.user.RoleWriteRead" type="public" client="User"> <Extends name="junit.framework.TestCase"/> <Import name="com.tlgen.common.trace.Trace"/> <Method name="create" parameter="User" client="User" manager="UserRole" typerwd="0"> <Exception name="com.tlgen.common.exception.PersistenceException"/> TLGen 145 StarData Gmb V 2.8 <Parameter type="%interfacedata%" /> </Method> <Method name="findByPrimaryKey" return="%interfacedata%" client="User" manager="UserRole" typerwd="1"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter type="%interfacedata%" /> <Parameter name="level" type="int" /> </Method> </Test> <Test name="eu.stardata.demo.client.test.user.UserWriteRead" type="public" client="User"> <Extends name="junit.framework.TestCase"/> <Import name="com.tlgen.common.trace.Trace"/> <Method name="create" parameter="User" client="User" manager="User" typerwd="0"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter type="%interfacedata%" /> </Method> <Method name="findByPrimaryKey" return="%interfacedata%" client="User" manager="User" typerwd="1"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter type="%interfacedata%" /> <Parameter name="level" type="int" /> </Method> <Method name="findByName" return="%interfacedata%[]" client="User" manager="User" typerwd="1"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter name="name" type="java.lang.String" /> <Parameter name="level" type="int" /> </Method> </Test> <Test name="eu.stardata.demo.client.test.user.UserTestMethods" type="public" client="User"> <Extends name="junit.framework.TestCase"/> <Import name="com.tlgen.common.trace.Trace"/> <Method name="findByLastName" return="%interfacedata%[]" client="User" manager="User" typerwd="13"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter name="lastName" type="java.lang.String" /> <Parameter name="level" type="int" /> </Method> <Method name="countUserTyp9" return="long" client="User" manager="User" typerwd="13"> <Exception name="com.tlgen.common.exception.PersistenceException"/> </Method> <Method name="demoUserFunction" return="java.util.List&#60;Object&#62;" client="User" manager="User" typerwd="13"> <Exception name="com.tlgen.common.exception.PersistenceException"/> </Method> <Method name="countUserTyp11" return="java.lang.Long" client="User" manager="User" typerwd="13"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter name="name" type="java.lang.String"/> </Method> </Design> methodtype="6"> </Test> <!-- ================================================= --> <!-- Design von Product Session --> <!-- ================================================= --> <Design name="product" methodreference="false"> <Commentary name="This is a generate package for 'product'"/> <!-- init the Manager Classes --> <Manager> <Method name="findByName" parameter="java.lang.String" return="%interfacedata%[]" manager="Product" <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter name="name" fullName="name" type="java.lang.String" /> <Sql name="getName" sql="select o from ProductEntity o where o.name = :name" /> manager="Product" methodtype="6"> </Method> <Method name="findByNameAndOffer" parameter="java.lang.String" return="%interfacedata%[]" <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter name="name" fullName="name" type="java.lang.String" /> <Parameter name="productOfferingId" fullName="productOfferingId" type="java.lang.String" /> <Sql name="getNameAndOffer" sql="select u from ProductEntity u where u.name = :name and u.productOfferingId = :productOfferingId" /> </Method> <Method name="findByMaterialnumber" parameter="java.lang.String" return="%interfacedata%[]" manager="Product" methodtype="6"> :materialNumber" /> TLGen <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter name="materialNumber" fullName="materialNumber" type="java.lang.String" /> <Sql name="getOffer" sql="select n from ProductEntity n where n.materialNumber = </Method> 146 StarData Gmb V 2.8 <Method name="FindByProductName" manager="Product" mapping="true" methodtype="8"> <Parameter name="name" type="java.lang.String"/> <Sql sql="SELECT * FROM Product WHERE name = ? ORDER BY Name" /> </Method> </Manager> <!-- init the Session Classes --> <!--Session> </Session--> <!-- init the Test Classes --> <Test name="eu.stardata.demo.client.test.product.ProductWriteRead" type="public" num="3" fileName="eu.stardata.demo.client.test.product.TestDataForProduct"> <Extends name="junit.framework.TestCase"/> <Import name="com.tlgen.common.trace.Trace"/> <Method name="create" client="Product" manager="Product" typerwd="0"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter type="%interfacedata%" manager="Product"/> </Method> <Method name="findByPrimaryKey" client="Product" return="%interfacedata%" manager="Product" typerwd="1"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter type="%interfacedata%" manager="Product"/> <Parameter name="level" type="int" /> </Method> <Method name="findByName" client="Product" return="%interfacedata%[]" manager="Product" typerwd="1"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter name="name" type="java.lang.String" /> <Parameter name="level" type="int" /> </Method> <Method name="findByNameAndOffer" client="Product" return="%interfacedata%[]" manager="Product" typerwd="1"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter name="name" type="java.lang.String" /> <Parameter name="offer" type="java.lang.String" /> <Parameter name="level" type="int" /> </Method> </Test> <Test name="eu.stardata.demo.client.test.product.ProductReadAll" type="public"> <Extends name="junit.framework.TestCase"/> <Import name="com.tlgen.common.trace.Trace"/> <Method name="findAll" return="%interfacedata%[]" manager="Product" client="Product" typerwd="1"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter name="von" type="int" /> <Parameter name="bis" type="int" /> <Parameter name="level" type="int" /> </Method> </Test> <Test name="eu.stardata.demo.client.test.product.ProductUpdate" type="public"> <Extends name="junit.framework.TestCase"/> <Import name="com.tlgen.common.trace.Trace"/> <Method name="update" manager="Product" client="Product" typerwd="2"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter type="%interfacedata%" manager="Product"/> </Method> </Test> <Test name="eu.stardata.demo.client.test.product.ProductDelete" type="public"> <Extends name="junit.framework.TestCase"/> <Import name="com.tlgen.common.trace.Trace"/> <Method name="delete" manager="Product" client="Product" typerwd="3"> <Exception name="com.tlgen.common.exception.PersistenceException"/> </Method> </Test> <Test name="eu.stardata.demo.client.test.product.ProductAttributeDelete" type="public"> <Extends name="junit.framework.TestCase"/> <Import name="com.tlgen.common.trace.Trace"/> <Method name="delete" manager="ProductAttribute" client="Product" typerwd="3"> <Exception name="com.tlgen.common.exception.PersistenceException"/> </Method> </Test> </Design> <!-- ================================================= --> <!-- Design von production Session --> <!-- ================================================= --> <Design name="production"> <Commentary name="This is a generate package for 'production'"/> <!-- init the Manager Classes --> <!--Manager> TLGen 147 StarData Gmb V 2.8 </Manager--> <!-- init the Session Classes --> <!--Session> </Session--> <!-- init the Test Classes --> <!-- init the free Classes --> <!--Freeclass> </Freeclass--> </Design> <!-- ================================================= --> <!-- Design von soap Session --> <!-- ================================================= --> <Design name="soap" > <Commentary name="This is a generate package for 'soap' for a Web Service"/> <!-- init the Manager Classes --> <!--Manager> </Manager--> <!-- init the Session Classes --> <Session name="eu.stardata.demo.server.persistence.soap.SoapSessionBean" transactiontype="JTA" sessionType="Web Service" inject="true"> methodtype="0"> <Extends name="com.tlgen.common.ejb.session.BaseSessionBean"/> <Client name="eu.stardata.demo.client.bci.soap.SoapBci"/> <Method name="updateUser" return="eu.stardata.demo.business.user.UserData" client="Soap" methodtype="0"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter name="user" type="eu.stardata.demo.business.user.UserData"/> </Method> <Method name="retrieveUser" return="java.util.List&#60;eu.stardata.demo.business.user.UserData&#62;" client="Soap" <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter name="name" type="java.lang.String"/> </Method> <Callback name = "eu.stardata.demo.server.persistence.soap.CallBackWeb ServiceUser" path ="C:/Projects/Project-Demo/source/soap" merge="1"/> </Session> <!-- init the Test Classes --> <Test name="eu.stardata.demo.client.test.soap.TestWeb ServiceUser" client="Soap"> <Method name="updateUser" return="eu.stardata.demo.business.user.UserData" client="Soap"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter name="update" type="eu.stardata.demo.business.user.UserData"/> </Method> <Method name="retrieveUser" return="java.util.List&#60;eu.stardata.demo.business.user.UserData&#62;" client="Soap"> <Exception name="com.tlgen.common.exception.PersistenceException"/> <Parameter name="name" type="java.lang.String"/> </Method> </Test> </Design> <!-- ================================================================ --> <!-- Design von rest Session --> <!-- Archive = 0 -> make in application.xml a jar file --> <!-1 -> make in application.xml a war file --> <!-2 -> make in application.xml a rar file --> <!-3 -> make in application.xml a jar and a war file file --> <!-- ================================================================ --> <Design name="rest" archive="3" methodreference="false"> <Commentary name="This is a transient file"/> <Commentary name="Session bean is a web service session bean for REST"/> <!-- init the Manager Classes --> <!--Manager> </Manager--> <!-- init the Session Classes --> <Session name="eu.stardata.demo.server.persistence.rest.RestSessionBean" transactiontype="JTA" sessionType="REST" intercep="false" inject="true" appPath="restApp" restPath="restSession"> <Extends name="com.tlgen.common.ejb.session.BaseSessionBean"/> <Annotation name="javax.ejb.TransactionAttribute"> <Parameter type="javax.ejb.TransactionAttributeType" content="REQUIRES_NEW"/> </Annotation> <Annotation name="org.jboss.resteasy.annotations.cache.NoCache"/> <Method name="createUser" return="eu.stardata.demo.business.user.UserJSon" client="Rest" rest="POST" methodtype="0"> <Exception name="java.lang.Exception"/> <Parameter name="user" type="eu.stardata.demo.business.user.UserJSon"/> </Method> <Method name="updateUser" return="eu.stardata.demo.business.user.UserJSon" client="Rest" rest="PUT" methodtype="0"> <Exception name="java.lang.Exception"/> TLGen 148 StarData Gmb V 2.8 <Parameter name="user" type="eu.stardata.demo.business.user.UserJSon"/> </Method> <Method name="deleteUser" return="java.lang.String" client="Rest" rest="DELETE" methodtype="0"> <Exception name="java.lang.Exception"/> <Parameter value="path" name="userId" type="long"/> </Method> <Method name="fetchUser" return="com.tlgen.common.rest.TlgListResponse&#60;eu.stardata.demo.business.user.UserJSon&#62;" client="Rest" rest="GET" methodtype="0"> <Exception name="java.lang.Exception"/> <Parameter default="" value="path" name="name" final="true" type="java.lang.String"/> </Method> <Method name="countUsers" return="long" client="Rest" rest="GET" methodtype="0"> <Exception name="java.lang.Exception"/> <!--Parameter value="path" name="userId" type="long"/--> <Parameter default="" value="query" name="name" final="true" type="java.lang.String"/> </Method> <Callback name = "eu.stardata.demo.server.rest.CallBackRest" callbackType="Session" path ="C:/Projects/Project-Demo/source/rest" merge="1"/> </Session> <!-- init the Test Classes --> <Test name="eu.stardata.demo.client.test.rest.TestRestUser" sessionType="REST"/> </Design> </Project> </Generator> 7.3 SQL Skript -- --------- Drop all Tables ----------DROP TABLE Product CASCADE CONSTRAINTS; DROP TABLE ServiceCost CASCADE CONSTRAINTS; DROP TABLE ProductRelation CASCADE CONSTRAINTS; DROP TABLE UserRole_UserTable CASCADE CONSTRAINTS; DROP TABLE ProductPrice CASCADE CONSTRAINTS; DROP TABLE UserRole CASCADE CONSTRAINTS; DROP TABLE CustomerServiceAttribute CASCADE CONSTRAINTS; DROP TABLE Classification CASCADE CONSTRAINTS; DROP TABLE UserTable CASCADE CONSTRAINTS; DROP TABLE CustomerService CASCADE CONSTRAINTS; DROP TABLE OrderTable CASCADE CONSTRAINTS; DROP TABLE ProductAttribute CASCADE CONSTRAINTS; DROP TABLE UserTable_Product CASCADE CONSTRAINTS; -- --------- Create Tables ----------CREATE TABLE Product ( Product_ID NUMBER(24,0) NOT NULL, -- the primary key of 'Product'; auto-generated by the DB EJB3_OPTLOCK NUMBER(16) NULL, -- EJB3 uses this value to realize the locking MODIFY_DATE TIMESTAMP(6) DEFAULT SYSDATE NULL, -- timestamp at which the table 'Product' has changed description VARCHAR2(255) NULL, -- / isVisibleInCustomerOfferOrInvo NUMBER(1,0) NULL, materialNumber VARCHAR2(255) NULL, name VARCHAR2(255) NULL, productOfferingId VARCHAR2(255) NULL, shortName VARCHAR2(255) NULL, CustomerService_ID NUMBER(24,0) NULL, -- connection to the table 'CustomerService' (foreign key) OrderTable_ID NUMBER(24,0) NULL, -- connection to the table 'OrderTable' (foreign key) CONSTRAINT Product_PK PRIMARY KEY (Product_ID) USING INDEX TABLESPACE COINDEX ) Tablespace CODATA; CREATE TABLE ServiceCost ( ServiceCost_ID NUMBER(24,0) NOT NULL, -- the primary key of 'ServiceCost'; auto-generated by the DB EJB3_OPTLOCK NUMBER(16) NULL, -- EJB3 uses this value to realize the locking MODIFY_DATE TIMESTAMP(6) DEFAULT SYSDATE NULL, -- timestamp at which the table 'ServiceCost' has changed allowanceUnitOfMeasure VARCHAR2(32) NULL, allowanceValue NUMBER(24,0) NULL, costType VARCHAR2(32) NULL, costValue NUMBER(28,4) NULL, -- / currency VARCHAR2(32) NULL, periodOfPaymentUnitOfMeasure VARCHAR2(32) NULL, validityPeriod TIMESTAMP(6) NULL, amount NUMBER(12,0) NULL, CustomerService_ID NUMBER(24,0) NULL, -- connection to the table 'CustomerService' (foreign key) CONSTRAINT ServiceCost_PK PRIMARY KEY (ServiceCost_ID) USING INDEX TABLESPACE COINDEX ) Tablespace CODATA; TLGen 149 StarData Gmb V 2.8 CREATE TABLE ProductRelation ( ProductRelation_ID NUMBER(24,0) NOT NULL, -- the primary key of 'ProductRelation'; auto-generated by the DB EJB3_OPTLOCK NUMBER(16) NULL, -- EJB3 uses this value to realize the locking MODIFY_DATE TIMESTAMP(6) DEFAULT SYSDATE NULL, -- timestamp at which the table 'ProductRelation' has changed name VARCHAR2(255) NULL, relationType VARCHAR2(32) NULL, Product_ID NUMBER(24,0) NULL, -- connection to the table 'Product' (foreign key) Parent_ID NUMBER(24,0) NULL, -- connection to the table 'Parent' (foreign key) CONSTRAINT ProductRelation_PK PRIMARY KEY (ProductRelation_ID) USING INDEX TABLESPACE COINDEX ) Tablespace CODATA; CREATE TABLE UserRole_UserTable ( UserRole_ID NUMBER(24,0) NOT NULL, -- the primary key of 'UserRole'; auto-generated by the DB UserTable_ID NUMBER(24,0) NOT NULL, -- the primary key of 'UserTable'; auto-generated by the DB CONSTRAINT UserRole_UserTable_PK PRIMARY KEY (UserRole_ID, UserTable_ID) USING INDEX TABLESPACE COINDEX ) Tablespace CODATA; CREATE TABLE ProductPrice ( ProductPrice_ID NUMBER(24,0) NOT NULL, -- the primary key of 'ProductPrice'; auto-generated by the DB EJB3_OPTLOCK NUMBER(16) NULL, -- EJB3 uses this value to realize the locking MODIFY_DATE TIMESTAMP(6) DEFAULT SYSDATE NULL, -- timestamp at which the table 'ProductPrice' has changed allowancePeriod TIMESTAMP(6) NULL, currency VARCHAR2(32) NULL, periodOfPaymentUnitOfMeasure VARCHAR2(32) NULL, priceType VARCHAR2(32) NULL, productOfferingPrice NUMBER(28,4) NULL, amount NUMBER(12,0) NULL, unitOfMeasure VARCHAR2(32) NULL, Product_ID NUMBER(24,0) NULL, -- connection to the table 'Product' (foreign key) CONSTRAINT ProductPrice_PK PRIMARY KEY (ProductPrice_ID) USING INDEX TABLESPACE COINDEX ) Tablespace CODATA; CREATE TABLE UserRole ( UserRole_ID NUMBER(24,0) NOT NULL, -- the primary key of 'UserRole'; auto-generated by the DB EJB3_OPTLOCK NUMBER(16) NULL, -- EJB3 uses this value to realize the locking MODIFY_DATE TIMESTAMP(6) DEFAULT SYSDATE NULL, -- timestamp at which the table 'UserRole' has changed RoleName VARCHAR2(32) NOT NULL, -- the name of the role as enum Description VARCHAR2(1024) NULL, -- description of the role CONSTRAINT UserRole_PK PRIMARY KEY (UserRole_ID) USING INDEX TABLESPACE COINDEX ) Tablespace CODATA; CREATE TABLE CustomerServiceAttribute ( CustomerServiceAttribute_ID NUMBER(24,0) NOT NULL, -- the primary key of 'CustomerServiceAttribute'; auto-generated by the DB EJB3_OPTLOCK NUMBER(16) NULL, -- EJB3 uses this value to realize the locking MODIFY_DATE TIMESTAMP(6) DEFAULT SYSDATE NULL, -- timestamp at which the table 'CustomerServiceAttribute' has changed description VARCHAR2(255) NULL, -- / name VARCHAR2(255) NULL, unit VARCHAR2(255) NULL, value VARCHAR2(255) NULL, CustomerService_ID NUMBER(24,0) NULL, -- connection to the table 'CustomerService' (foreign key) CONSTRAINT CustomerServiceAttribute_PK PRIMARY KEY (CustomerServiceAttribute_ID) USING INDEX TABLESPACE COINDEX ) Tablespace CODATA; CREATE TABLE Classification ( Classification_ID NUMBER(24,0) NOT NULL, -- the primary key of 'Classification'; auto-generated by the DB EJB3_OPTLOCK NUMBER(16) NULL, -- EJB3 uses this value to realize the locking MODIFY_DATE TIMESTAMP(6) DEFAULT SYSDATE NULL, -- timestamp at which the table 'Classification' has changed classificationSpecificationId VARCHAR2(255) NULL, classSpecificationId VARCHAR2(255) NULL, name VARCHAR2(255) NULL, Product_ID NUMBER(24,0) NULL, -- connection to the table 'Product' (foreign key) CustomerService_ID NUMBER(24,0) NULL, -- connection to the table 'CustomerService' (foreign key) CONSTRAINT Classification_PK PRIMARY KEY (Classification_ID) USING INDEX TABLESPACE COINDEX ) Tablespace CODATA; -- This table contains the internal accounts which are permitted to access the Demo system. CREATE TABLE UserTable ( UserTable_ID NUMBER(24,0) NOT NULL, -- the primary key of 'UserTable'; auto-generated by the DB EJB3_OPTLOCK NUMBER(16) NULL, -- EJB3 uses this value to realize the locking MODIFY_DATE TIMESTAMP(6) DEFAULT SYSDATE NULL, -- timestamp at which the table 'UserTable' has changed Email VARCHAR2(512) NULL, -- the email of the user FirstName VARCHAR2(255) NULL, -- the first name(s) of the user LastName VARCHAR2(255) NULL, -- the last name of the user UserName VARCHAR2(24) NOT NULL, -- the username of the according Demo account PassWord VARCHAR2(24) NOT NULL, -- the pasword to access to the Demo program TLGen 150 StarData Gmb V 2.8 CONSTRAINT UserTable_PK PRIMARY KEY (UserTable_ID) USING INDEX TABLESPACE COINDEX ) Tablespace CODATA; CREATE TABLE CustomerService ( CustomerService_ID NUMBER(24,0) NOT NULL, -- the primary key of 'CustomerService'; auto-generated by the DB EJB3_OPTLOCK NUMBER(16) NULL, -- EJB3 uses this value to realize the locking MODIFY_DATE TIMESTAMP(6) DEFAULT SYSDATE NULL, -- timestamp at which the table 'CustomerService' has changed customerFacingServiceSpecId VARCHAR2(255) NULL, description VARCHAR2(255) NULL, materialNumber VARCHAR2(255) NULL, name VARCHAR2(255) NULL, shortName VARCHAR2(255) NULL, status VARCHAR2(255) NULL, version VARCHAR2(255) NULL, CONSTRAINT CustomerService_PK PRIMARY KEY (CustomerService_ID) USING INDEX TABLESPACE COINDEX ) Tablespace CODATA; -- the order class CREATE TABLE OrderTable ( OrderTable_ID NUMBER(24,0) NOT NULL, -- the primary key of 'OrderTable'; auto-generated by the DB EJB3_OPTLOCK NUMBER(16) NULL, -- EJB3 uses this value to realize the locking MODIFY_DATE TIMESTAMP(6) DEFAULT SYSDATE NULL, -- timestamp at which the table 'OrderTable' has changed OrderNumber VARCHAR2(32) NOT NULL, -- the order number Created TIMESTAMP(6) NULL, -- the date of order created OrderQuantity NUMBER(12,0) NOT NULL, CONSTRAINT OrderTable_PK PRIMARY KEY (OrderTable_ID) USING INDEX TABLESPACE COINDEX ) Tablespace CODATA; CREATE TABLE ProductAttribute ( ProductAttribute_ID NUMBER(24,0) NOT NULL, -- the primary key of 'ProductAttribute'; auto-generated by the DB EJB3_OPTLOCK NUMBER(16) NULL, -- EJB3 uses this value to realize the locking MODIFY_DATE TIMESTAMP(6) DEFAULT SYSDATE NULL, -- timestamp at which the table 'ProductAttribute' has changed description VARCHAR2(255) NULL, name VARCHAR2(255) NULL, -- / specificationCharacteristicId VARCHAR2(255) NULL, unitOfMeasure VARCHAR2(255) NULL, value VARCHAR2(255) NULL, -- / Product_ID NUMBER(24,0) NULL, -- connection to the table 'Product' (foreign key) CONSTRAINT ProductAttribute_PK PRIMARY KEY (ProductAttribute_ID) USING INDEX TABLESPACE COINDEX ) Tablespace CODATA; CREATE TABLE UserTable_Product ( UserTable_ID NUMBER(24,0) NOT NULL, -- the primary key of 'UserTable'; auto-generated by the DB Product_ID NUMBER(24,0) NOT NULL, -- the primary key of 'Product'; auto-generated by the DB CONSTRAINT UserTable_Product_PK PRIMARY KEY (UserTable_ID, Product_ID) USING INDEX TABLESPACE COINDEX ) Tablespace CODATA; -- --- Foreign key -----ALTER TABLE Product ADD CONSTRAINT Product_1FK FOREIGN KEY (CustomerService_ID) REFERENCES CustomerService; ALTER TABLE Product ADD CONSTRAINT Product_2FK FOREIGN KEY (OrderTable_ID) REFERENCES OrderTable; ALTER TABLE ServiceCost ADD CONSTRAINT ServiceCost_1FK FOREIGN KEY (CustomerService_ID) REFERENCES CustomerService; ALTER TABLE ProductRelation ADD CONSTRAINT ProductRelation_1FK FOREIGN KEY (Product_ID) REFERENCES Product; ALTER TABLE ProductRelation ADD CONSTRAINT ProductRelation_2FK FOREIGN KEY (Parent_ID) REFERENCES ProductRelation; ALTER TABLE ProductPrice ADD CONSTRAINT ProductPrice_1FK FOREIGN KEY (Product_ID) REFERENCES Product; ALTER TABLE CustomerServiceAttribute ADD CONSTRAINT CustomerServiceAttribute_1FK FOREIGN KEY (CustomerService_ID) REFERENCES CustomerService; ALTER TABLE Classification ADD CONSTRAINT Classification_1FK FOREIGN KEY (Product_ID) REFERENCES Product; ALTER TABLE Classification ADD CONSTRAINT Classification_2FK FOREIGN KEY (CustomerService_ID) REFERENCES CustomerService; ALTER TABLE ProductAttribute ADD CONSTRAINT ProductAttribute_1FK FOREIGN KEY (Product_ID) REFERENCES Product; -- --------- Drop all Sequences ----------DROP SEQUENCE Product_Product_ID_1SQ; DROP SEQUENCE ServiceCost_ServiceCost_ID_1SQ; DROP SEQUENCE ProductRelation_ProductRel_1SQ; DROP SEQUENCE UserRole_UserTable_UserRol_1SQ; DROP SEQUENCE ProductPrice_ProductPrice__1SQ; DROP SEQUENCE UserRole_UserRole_ID_1SQ; DROP SEQUENCE CustomerServiceAttribute_C_1SQ; DROP SEQUENCE Classification_Classificat_1SQ; DROP SEQUENCE UserTable_UserTable_ID_1SQ; DROP SEQUENCE CustomerService_CustomerSe_1SQ; DROP SEQUENCE OrderTable_OrderTable_ID_1SQ; DROP SEQUENCE ProductAttribute_ProductAt_1SQ; DROP SEQUENCE UserTable_Product_UserTabl_1SQ; -- --------- Create Sequences ----------CREATE SEQUENCE Product_Product_ID_1SQ START WITH 1 INCREMENT BY 1 CACHE 10 MINVALUE 1; TLGen 151 StarData Gmb V 2.8 CREATE SEQUENCE ServiceCost_ServiceCost_ID_1SQ START WITH 1 INCREMENT BY 1 CACHE 10 MINVALUE 1; CREATE SEQUENCE ProductRelation_ProductRel_1SQ START WITH 1 INCREMENT BY 1 CACHE 10 MINVALUE 1; CREATE SEQUENCE UserRole_UserTable_UserRol_1SQ; CREATE SEQUENCE ProductPrice_ProductPrice__1SQ START WITH 1 INCREMENT BY 1 CACHE 10 MINVALUE 1; CREATE SEQUENCE UserRole_UserRole_ID_1SQ START WITH 1 INCREMENT BY 1 CACHE 10 MINVALUE 1; CREATE SEQUENCE CustomerServiceAttribute_C_1SQ START WITH 1 INCREMENT BY 1 CACHE 10 MINVALUE 1; CREATE SEQUENCE Classification_Classificat_1SQ START WITH 1 INCREMENT BY 1 CACHE 10 MINVALUE 1; CREATE SEQUENCE UserTable_UserTable_ID_1SQ START WITH 1 INCREMENT BY 1 CACHE 10 MINVALUE 1; CREATE SEQUENCE CustomerService_CustomerSe_1SQ START WITH 1 INCREMENT BY 1 CACHE 10 MINVALUE 1; CREATE SEQUENCE OrderTable_OrderTable_ID_1SQ START WITH 1 INCREMENT BY 1 CACHE 10 MINVALUE 1; CREATE SEQUENCE ProductAttribute_ProductAt_1SQ START WITH 1 INCREMENT BY 1 CACHE 10 MINVALUE 1; CREATE SEQUENCE UserTable_Product_UserTabl_1SQ; -- ------- Constraints ---------- ------- Foreign key index --------create index Product_1UQ on Product (CustomerService_ID) tablespace COINDEX; create index Product_2UQ on Product (OrderTable_ID) tablespace COINDEX; create index ServiceCost_1UQ on ServiceCost (CustomerService_ID) tablespace COINDEX; create index ProductRelation_1UQ on ProductRelation (Product_ID) tablespace COINDEX; create index ProductRelation_2UQ on ProductRelation (Parent_ID) tablespace COINDEX; create index ProductPrice_1UQ on ProductPrice (Product_ID) tablespace COINDEX; create index CustomerServiceAttribute_1UQ on CustomerServiceAttribute (CustomerService_ID) tablespace COINDEX; create index Classification_1UQ on Classification (Product_ID) tablespace COINDEX; create index Classification_2UQ on Classification (CustomerService_ID) tablespace COINDEX; create index ProductAttribute_1UQ on ProductAttribute (Product_ID) tablespace COINDEX; -- --- Table, Columns and Sequences was changes ------ 7.4 Klassen und Interfaces 7.4.1 Data-Klassen /** * **** do not change with a file editor ***** */ package eu.stardata.demo.business.user; import eu.stardata.demo.business.user.UserRoleData; import java.util.Date; import java.lang.String; import java.io.Serializable; import eu.stardata.demo.business.product.ProductData; import java.util.List; /** * This is a generate package for 'user' * * This table contains the internal accounts which are permitted to access the Demo system. */ public class UserData implements Serializable { private static final long serialVersionUID = 319770677; // Methods from columns private long m_ejb3Optlock; private String m_email; private String m_passWord; private String m_firstName; private long m_userID; private String m_userName; private String m_lastName; private Date m_modifyDate; // Methods from relations tables private List<ProductData> m_product; private List<UserRoleData> m_userRole; // Methods from columns public long getEjb3Optlock() { return m_ejb3Optlock; } TLGen 152 StarData Gmb V 2.8 public void setEjb3Optlock(long arg) { m_ejb3Optlock = arg; } /** * the email of the user */ public String getEmail() { return m_email; } public void setEmail(String arg) { m_email = arg; } /** * the pasword to access to the Demo program */ public String getPassWord() { return m_passWord; } public void setPassWord(String arg) { m_passWord = arg; } /** * the first name(s) of the user */ public String getFirstName() { return m_firstName; } public void setFirstName(String arg) { m_firstName = arg; } public long getUserID() { return m_userID; } public void setUserID(long arg) { m_userID = arg; } /** * the username of the according Demo account */ public String getUserName() { return m_userName; } public void setUserName(String arg) { m_userName = arg; } /** * the last name of the user */ public String getLastName() { return m_lastName; } public void setLastName(String arg) { m_lastName = arg; } public Date getModifyDate() { return m_modifyDate; } public void setModifyDate(Date arg) { m_modifyDate = arg; } // Methods from relations tables TLGen 153 StarData Gmb V 2.8 public List<ProductData> getProduct() { return m_product; } public void setProduct(List<ProductData> arg) { m_product = arg; } public List<UserRoleData> getUserRole() { return m_userRole; } public void setUserRole(List<UserRoleData> arg) { m_userRole = arg; } } 7.4.2 Interface-Data Falls Verwendet /** * Generated by TLGEN - Do not edit! * Version 2.8.002 * * Legt alle Nutzer des Projekt fest. * */ //====================================================================== package de.stardata.demo.business.user.dataif; import de.stardata.demo.business.types.LockForLogin; import de.stardata.demo.business.types.Authentification; import de.stardata.demo.business.types.AccessHistoryConfig; import com.tlgen.common.data.BaseDataIf; import java.util.List; import de.stardata.demo.business.user.dataif.UserRoleDataIf; public interface UserDataIf extends BaseDataIf { // Methods from columns public abstract Authentification getAuthentification(); public abstract void setAuthentification(Authentification arg); /** * Max. number of access entries to be stored for this user (in the table ACCESSHISTORY) * */ public abstract AccessHistoryConfig getAccessHistoryConfig(); public abstract void setAccessHistoryConfig(AccessHistoryConfig arg); public abstract long getUserID(); public abstract void setUserID(long arg); public abstract LockForLogin getLock(); public abstract void setLock(LockForLogin arg); public abstract long getDbVersion(); public abstract void setDbVersion(long arg); } TLGen // Methods from relations tables public abstract List<UserRoleDataIf> getUserRole(); public abstract void setUserRole(List<UserRoleDataIf> arg); 154 StarData Gmb V 2.8 7.4.3 JSon Data-Klasse /** * **** do not change with a file editor ***** */ package eu.stardata.demo.business.user; import javax.xml.bind.annotation.XmlRootElement; import eu.stardata.demo.business.product.ProductJSon; import eu.stardata.demo.business.user.UserRoleJSon; import java.util.Date; import java.lang.String; import java.io.Serializable; import java.util.List; /** * This is a generate package for 'user' * * This table contains the internal accounts which are permitted to access the Demo system. */ @XmlRootElement(name = "user") public class UserJSon implements Serializable { private static final long serialVersionUID = 741075541; // Methods from columns private long ejb3Optlock; private String email; private String passWord; private String firstName; private long userID; private String userName; private String lastName; private Date modifyDate; // Methods from relations tables private List<ProductJSon> product; private List<UserRoleJSon> userRole; // Methods from columns public long getEjb3Optlock() { return ejb3Optlock; } public void setEjb3Optlock(long arg) { ejb3Optlock = arg; } public String getEmail() { return email; } public void setEmail(String arg) { email = arg; } public String getPassWord() { return passWord; } public void setPassWord(String arg) { passWord = arg; } public String getFirstName() { return firstName; } public void setFirstName(String arg) { firstName = arg; } public long getUserID() { return userID; } public void setUserID(long arg) { TLGen 155 StarData Gmb V 2.8 } userID = arg; public String getUserName() { return userName; } public void setUserName(String arg) { userName = arg; } public String getLastName() { return lastName; } public void setLastName(String arg) { lastName = arg; } public Date getModifyDate() { return modifyDate; } public void setModifyDate(Date arg) { modifyDate = arg; } // Methods from relations tables public List<ProductJSon> getProduct() { return product; } public void setProduct(List<ProductJSon> arg) { product = arg; } public List<UserRoleJSon> getUserRole() { return userRole; } } public void setUserRole(List<UserRoleJSon> arg) { userRole = arg; } 7.4.4 Mapping zwischen Data-Klassen und JSon Klasse /** * **** do not change with a file editor ***** */ package eu.stardata.demo.business.user; import eu.stardata.demo.business.user.UserRoleData; import eu.stardata.demo.business.product.ProductJSon; import eu.stardata.demo.business.user.UserRoleJSon; import eu.stardata.demo.business.product.ProductMap; import eu.stardata.demo.business.user.UserRoleMap; import eu.stardata.demo.business.user.UserJSon; import java.util.ArrayList; import eu.stardata.demo.business.user.UserData; import java.io.Serializable; import eu.stardata.demo.business.product.ProductData; import java.util.List; /** * This class map the class data to JSon class data and inverse */ public class UserMap implements Serializable { private static final long serialVersionUID = 95856718; // Mapping methods between class data and JSon data objects /** TLGen 156 StarData Gmb V 2.8 * Map "UserData" object to "UserJSon" object data * @param json * @return */ public static UserData mapJSonToData(UserJSon json) { UserData data = new UserData(); data.setEjb3Optlock(json.getEjb3Optlock()); data.setEmail(json.getEmail()); data.setPassWord(json.getPassWord()); data.setFirstName(json.getFirstName()); data.setUserID(json.getUserID()); data.setUserName(json.getUserName()); data.setLastName(json.getLastName()); data.setModifyDate(json.getModifyDate()); data.setProduct(getProductJSonList(json.getProduct())); data.setUserRole(getUserRoleJSonList(json.getUserRole())); return data; } /** * Map "UserJSon" object to "UserData" object data * @param data * @return */ public static UserJSon mapDataToJSon(UserData data) { UserJSon json = new UserJSon(); json.setEjb3Optlock(data.getEjb3Optlock()); json.setEmail(data.getEmail()); json.setPassWord(data.getPassWord()); json.setFirstName(data.getFirstName()); json.setUserID(data.getUserID()); json.setUserName(data.getUserName()); json.setLastName(data.getLastName()); json.setModifyDate(data.getModifyDate()); json.setProduct(getProductDataList(data.getProduct())); json.setUserRole(getUserRoleDataList(data.getUserRole())); } return json; /** * Helper method for mapping * @param data * @return */ private static List<ProductData> getProductJSonList(List<ProductJSon> list) { List<ProductData> listProduct = null; if(list != null && !list.isEmpty()) { listProduct = new ArrayList<ProductData>(); for(ProductJSon json : list) { if(json != null) { ProductData data = ProductMap.mapJSonToData(json); listProduct.add(data); } } } return listProduct; } /** * Helper method for mapping * @param data * @return */ private static List<UserRoleData> getUserRoleJSonList(List<UserRoleJSon> list) { List<UserRoleData> listUserRole = null; if(list != null && !list.isEmpty()) { listUserRole = new ArrayList<UserRoleData>(); for(UserRoleJSon json : list) { if(json != null) { UserRoleData data = UserRoleMap.mapJSonToData(json); listUserRole.add(data); TLGen 157 StarData Gmb V 2.8 } } } return listUserRole; } /** * Helper method for mapping * @param data * @return */ private static List<ProductJSon> getProductDataList(List<ProductData> list) { List<ProductJSon> listProduct = null; if(list != null && !list.isEmpty()) { listProduct = new ArrayList<ProductJSon>(); for(ProductData data : list) { if(data != null) { ProductJSon json = ProductMap.mapDataToJSon(data); listProduct.add(json); } } } return listProduct; } } /** * Helper method for mapping * @param data * @return */ private static List<UserRoleJSon> getUserRoleDataList(List<UserRoleData> list) { List<UserRoleJSon> listUserRole = null; if(list != null && !list.isEmpty()) { listUserRole = new ArrayList<UserRoleJSon>(); for(UserRoleData data : list) { if(data != null) { UserRoleJSon json = UserRoleMap.mapDataToJSon(data); listUserRole.add(json); } } } return listUserRole; } 7.5 Session Bean 7.5.1 Session Bean-Klassen /** * **** do not change with a file editor ***** */ package eu.stardata.demo.server.persistence.user; import eu.stardata.demo.business.user.UserRoleData; import eu.stardata.demo.server.persistence.user.managerif.OrderManagerIf; import java.lang.Long; import javax.persistence.NamedNativeQueries; import javax.persistence.SqlResultSetMapping; import eu.stardata.demo.business.user.FindByLastNameData; import eu.stardata.demo.server.persistence.user.TimeCore; import eu.stardata.demo.server.persistence.user.managerif.UserManagerIf; import eu.stardata.demo.business.user.OrderData; import javax.persistence.NamedNativeQuery; import eu.stardata.demo.business.user.UserData; import javax.persistence.SqlResultSetMappings; import javax.interceptor.Interceptors; import eu.stardata.demo.server.persistence.user.TimeCore; import javax.ejb.Stateless; import eu.stardata.demo.client.bci.user.UserBci; import eu.stardata.demo.server.persistence.user.managerif.UserRoleManagerIf; import javax.ejb.Remote; TLGen 158 StarData Gmb V 2.8 import java.lang.String; import javax.ejb.EJB; import com.tlgen.common.exception.PersistenceException; import java.util.List; /** * This is a generate package for 'user' * * A session bean encapsulates business logic that can be invoked programmatically * by a client over local, remote, or web service client views. */ @Stateless(name = UserBci.JNDI_NAME, mappedName = "demo/"+UserBci.JNDI_NAME+"/remote") @Remote(UserBci.class) @Interceptors(TimeCore.class) public class UserSessionBean implements UserBci { // Session annotations and fields for local manager @EJB private UserManagerIf m_UserManagerIf; @EJB private UserRoleManagerIf m_UserRoleManagerIf; @EJB private OrderManagerIf m_OrderManagerIf; /** * Default Constructor */ public UserSessionBean() { super(); } // Session class methods /** * Session method "findByLastNameUser()" * @param name * @param level * @return * @throws PersistenceException */ public List<FindByLastNameData> findByLastNameUser(String name, int level) throws PersistenceException { try { return m_UserManagerIf.findByLastName(name, level); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "clearUserRole()" * @throws PersistenceException */ public void clearUserRole() throws PersistenceException { try { m_UserRoleManagerIf.clear(); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "clearOrder()" * @throws PersistenceException */ public void clearOrder() throws PersistenceException { try { m_OrderManagerIf.clear(); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "findAllUser()" * @param from TLGen 159 StarData Gmb V 2.8 * @param to * @param level * @return * @throws PersistenceException */ public UserData[] findAllUser(int from, int to, int level) throws PersistenceException { try { return m_UserManagerIf.findAll(from, to, level); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "findAllUserRole()" * @param from * @param to * @param level * @return * @throws PersistenceException */ public UserRoleData[] findAllUserRole(int from, int to, int level) throws PersistenceException { try { return m_UserRoleManagerIf.findAll(from, to, level); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "closeUser()" * @throws PersistenceException */ public void closeUser() throws PersistenceException { try { m_UserManagerIf.close(); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "findByNameUser()" * @param name * @param level * @return * @throws PersistenceException */ public UserData[] findByNameUser(String name, int level) throws PersistenceException { try { return m_UserManagerIf.findByName(name, level); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "demoUserFunctionUser()" * @throws PersistenceException */ public List<Object> demoUserFunctionUser() throws PersistenceException { try { return m_UserManagerIf.demoUserFunction(); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "detachUser()" * @param arg * @return * @throws PersistenceException */ public void detachUser(UserData arg) throws PersistenceException { try { m_UserManagerIf.detach(arg); TLGen 160 StarData Gmb V 2.8 } } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } /** * Session method "flushUser()" * @throws PersistenceException */ public void flushUser() throws PersistenceException { try { m_UserManagerIf.flush(); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "removeUserRole()" * @param arg * @return * @throws PersistenceException */ public void removeUserRole(UserRoleData arg) throws PersistenceException { try { m_UserRoleManagerIf.remove(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "flushUserRole()" * @throws PersistenceException */ public void flushUserRole() throws PersistenceException { try { m_UserRoleManagerIf.flush(); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "countUserTyp9User()" * @throws PersistenceException */ public List<Object> countUserTyp9User() throws PersistenceException { try { return m_UserManagerIf.countUserTyp9(); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "readUpdateUserRole()" * @param arg * @return * @throws PersistenceException */ public void readUpdateUserRole(UserRoleData arg) throws PersistenceException { try { m_UserRoleManagerIf.readUpdate(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "detachOrder()" * @param arg * @return * @throws PersistenceException */ public void detachOrder(OrderData arg) throws PersistenceException { try { TLGen 161 StarData Gmb V 2.8 m_OrderManagerIf.detach(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "removeUser()" * @param arg * @return * @throws PersistenceException */ public void removeUser(UserData arg) throws PersistenceException { try { m_UserManagerIf.remove(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "updateUserRole()" * @param arg * @return * @throws PersistenceException */ public void updateUserRole(UserRoleData arg) throws PersistenceException { try { m_UserRoleManagerIf.update(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "createUserRole()" * @param arg * @return * @throws PersistenceException */ public UserRoleData createUserRole(UserRoleData arg) throws PersistenceException { try { return m_UserRoleManagerIf.create(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "readUpdateUser()" * @param arg * @return * @throws PersistenceException */ public void readUpdateUser(UserData arg) throws PersistenceException { try { m_UserManagerIf.readUpdate(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "flushOrder()" * @throws PersistenceException */ public void flushOrder() throws PersistenceException { try { m_OrderManagerIf.flush(); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "fullUpdateUser()" * @param arg TLGen 162 StarData Gmb V 2.8 * @return * @throws PersistenceException */ public void fullUpdateUser(UserData arg) throws PersistenceException { try { m_UserManagerIf.fullUpdate(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "clearUser()" * @throws PersistenceException */ public void clearUser() throws PersistenceException { try { m_UserManagerIf.clear(); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "updateOrder()" * @param arg * @return * @throws PersistenceException */ public void updateOrder(OrderData arg) throws PersistenceException { try { m_OrderManagerIf.update(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "findAllOrder()" * @param from * @param to * @param level * @return * @throws PersistenceException */ public OrderData[] findAllOrder(int from, int to, int level) throws PersistenceException { try { return m_OrderManagerIf.findAll(from, to, level); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "closeUserRole()" * @throws PersistenceException */ public void closeUserRole() throws PersistenceException { try { m_UserRoleManagerIf.close(); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "readUpdateOrder()" * @param arg * @return * @throws PersistenceException */ public void readUpdateOrder(OrderData arg) throws PersistenceException { try { m_OrderManagerIf.readUpdate(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } TLGen 163 StarData Gmb V 2.8 } /** * Session method "detachUserRole()" * @param arg * @return * @throws PersistenceException */ public void detachUserRole(UserRoleData arg) throws PersistenceException { try { m_UserRoleManagerIf.detach(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "createOrder()" * @param arg * @return * @throws PersistenceException */ public OrderData createOrder(OrderData arg) throws PersistenceException { try { return m_OrderManagerIf.create(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "fullUpdateUserRole()" * @param arg * @return * @throws PersistenceException */ public void fullUpdateUserRole(UserRoleData arg) throws PersistenceException { try { m_UserRoleManagerIf.fullUpdate(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "createUser()" * @param arg * @return * @throws PersistenceException */ public UserData createUser(UserData arg) throws PersistenceException { try { return m_UserManagerIf.create(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "findByPrimaryKeyOrder()" * @param arg * @param level * @return * @throws PersistenceException */ public OrderData findByPrimaryKeyOrder(OrderData arg, int level) throws PersistenceException { try { return m_OrderManagerIf.findByPrimaryKey(arg, level); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "findByPrimaryKeyUserRole()" * @param arg * @param level TLGen 164 StarData Gmb V 2.8 * @return * @throws PersistenceException */ public UserRoleData findByPrimaryKeyUserRole(UserRoleData arg, int level) throws PersistenceException { try { return m_UserRoleManagerIf.findByPrimaryKey(arg, level); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "findByPrimaryKeyUser()" * @param arg * @param level * @return * @throws PersistenceException */ public UserData findByPrimaryKeyUser(UserData arg, int level) throws PersistenceException { try { return m_UserManagerIf.findByPrimaryKey(arg, level); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "closeOrder()" * @throws PersistenceException */ public void closeOrder() throws PersistenceException { try { m_OrderManagerIf.close(); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "removeOrder()" * @param arg * @return * @throws PersistenceException */ public void removeOrder(OrderData arg) throws PersistenceException { try { m_OrderManagerIf.remove(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "fullUpdateOrder()" * @param arg * @return * @throws PersistenceException */ public void fullUpdateOrder(OrderData arg) throws PersistenceException { try { m_OrderManagerIf.fullUpdate(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "updateUser()" * @param arg * @return * @throws PersistenceException */ public void updateUser(UserData arg) throws PersistenceException { try { m_UserManagerIf.update(arg); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); TLGen 165 StarData Gmb V 2.8 } } /** * Session method "countUserTyp11User()" * @param name * @return * @throws PersistenceException */ public Long countUserTyp11User(String name) throws PersistenceException { try { return m_UserManagerIf.countUserTyp11(name); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } } 7.5.2 Session Bean Interface /** * **** do not change with a file editor ***** */ package eu.stardata.demo.client.bci.user; import eu.stardata.demo.business.user.UserRoleData; import eu.stardata.demo.business.user.FindByLastNameData; import javax.ejb.Remote; import java.lang.String; import eu.stardata.demo.business.user.OrderData; import eu.stardata.demo.business.user.UserData; import com.tlgen.common.exception.PersistenceException; import java.util.List; @Remote public interface UserBci { // Client interface Fields public final static String JNDI_NAME_PREFIX = "demo"; public final static String JNDI_NAME = "eu.stardata.demo.server.persistence.user.UserSessionBean"; public final static String MANAGER_NAME = "managerDemo"; public final static String EAR_NAME = "demo"; public final static String PACKAGE_NAME = "user"; // Session - Client interface methods public List<FindByLastNameData> findByLastNameUser(String name, int level) throws PersistenceException; public void clearUserRole() throws PersistenceException; public void clearOrder() throws PersistenceException; public eu.stardata.demo.business.user.UserData[] findAllUser(int from, int to, int level) throws PersistenceException; public eu.stardata.demo.business.user.UserRoleData[] findAllUserRole(int from, int to, int level) throws PersistenceException; public void closeUser() throws PersistenceException; public eu.stardata.demo.business.user.UserData[] findByNameUser(String name, int level) throws PersistenceException; public List<Object> demoUserFunctionUser() throws PersistenceException; public void detachUser(UserData arg) throws PersistenceException; public void flushUser() throws PersistenceException; public void removeUserRole(UserRoleData arg) throws PersistenceException; public void flushUserRole() throws PersistenceException; public List<Object> countUserTyp9User() throws PersistenceException; public void readUpdateUserRole(UserRoleData arg) throws PersistenceException; TLGen 166 StarData Gmb V 2.8 public void detachOrder(OrderData arg) throws PersistenceException; public void removeUser(UserData arg) throws PersistenceException; public void updateUserRole(UserRoleData arg) throws PersistenceException; public UserRoleData createUserRole(UserRoleData arg) throws PersistenceException; public void readUpdateUser(UserData arg) throws PersistenceException; public void flushOrder() throws PersistenceException; public void fullUpdateUser(UserData arg) throws PersistenceException; public void clearUser() throws PersistenceException; public void updateOrder(OrderData arg) throws PersistenceException; public eu.stardata.demo.business.user.OrderData[] findAllOrder(int from, int to, int level) throws PersistenceException; public void closeUserRole() throws PersistenceException; public void readUpdateOrder(OrderData arg) throws PersistenceException; public void detachUserRole(UserRoleData arg) throws PersistenceException; public OrderData createOrder(OrderData arg) throws PersistenceException; public void fullUpdateUserRole(UserRoleData arg) throws PersistenceException; public UserData createUser(UserData arg) throws PersistenceException; public OrderData findByPrimaryKeyOrder(OrderData arg, int level) throws PersistenceException; public UserRoleData findByPrimaryKeyUserRole(UserRoleData arg, int level) throws PersistenceException; public UserData findByPrimaryKeyUser(UserData arg, int level) throws PersistenceException; public void closeOrder() throws PersistenceException; public void removeOrder(OrderData arg) throws PersistenceException; public void fullUpdateOrder(OrderData arg) throws PersistenceException; public void updateUser(UserData arg) throws PersistenceException; } public java.lang.Long countUserTyp11User(String name) throws PersistenceException; 7.5.3 Client Factory-Klasse /** * **** do not change with a file editor ***** */ package eu.stardata.demo.client.bci.user; import eu.stardata.demo.client.bci.user.UserBci; import com.tlgen.common.exception.PersistenceException; import com.tlgen.common.bci.BciFactory; /** * This is a generate package for 'user' * * The client of an enterprise bean obtains a reference * to an instance of an enterprise bean. */ public class UserBciFactory extends BciFactory { /** * getUserBci() */ public static synchronized UserBci getUserBci() throws PersistenceException { return (UserBci)getBciImplementation(UserBci.class); TLGen 167 StarData Gmb V 2.8 } } 7.5.4 Session Bean REST Interface /** * **** do not change with a file editor ***** */ package eu.stardata.demo.server.persistence.rest; import java.lang.Exception; import javax.ws.rs.DefaultValue; import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; import javax.ws.rs.Path; import javax.ws.rs.POST; import javax.ws.rs.GET; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import java.lang.String; import com.tlgen.common.rest.TlgListResponse; import eu.stardata.demo.business.user.UserJSon; import javax.ws.rs.Produces; import javax.ws.rs.PUT; @Path("/restSession") public interface RestSession { // Client interface Fields public final static String JNDI_NAME_PREFIX = "demo"; public final static String JNDI_NAME = "eu.stardata.demo.server.persistence.rest.RestSessionBean"; public final static String MANAGER_NAME = "managerDemo"; public final static String EAR_NAME = "demo"; public final static String PACKAGE_NAME = "rest"; // Session - Client interface methods @GET @Path("/fetchUser/{name}") @Produces("application/json") public TlgListResponse<UserJSon> fetchUser(@PathParam("name") final @DefaultValue("") String name) throws Exception; @POST @Path("/createUser") @Consumes("application/json") @Produces("application/json") public UserJSon createUser(UserJSon user) throws Exception; @GET @Path("/countUsers") @Produces("application/json") public long countUsers(@QueryParam("name") final @DefaultValue("") String name) throws Exception; @DELETE @Path("/deleteUser/{userId}") @Produces("application/json") public String deleteUser(@PathParam("userId") long userId) throws Exception; @PUT @Path("/updateUser") @Consumes("application/json") @Produces("application/json") public UserJSon updateUser(UserJSon user) throws Exception; } 7.6 Entity Manager Bean 7.6.1 Entity Manager Bean-Klasse TLGen 168 StarData Gmb V 2.8 /** * **** do not change with a file editor ***** */ package eu.stardata.demo.server.persistence.user.manager; import java.util.ArrayList; import java.util.List; import javax.ejb.EJB; import javax.ejb.Local; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import com.tlgen.common.bci.ServiceLocator; import com.tlgen.common.exception.PersistenceException; import eu.stardata.demo.business.user.FindByLastNameData; import eu.stardata.demo.business.user.UserData; import eu.stardata.demo.client.bci.user.UserBci; import eu.stardata.demo.server.criteria.user.UserCriteria; import eu.stardata.demo.server.persistence.product.managerif.ProductManagerIf; import eu.stardata.demo.server.persistence.user.entity.UserEntity; import eu.stardata.demo.server.persistence.user.managerif.UserManagerIf; /** * This is a generate package for 'user' * * Entities are managed by the entity manager, * which is represented by javax.persistence.EntityManager instances. * Each EntityManager instance is associated with a persistence context. */ @Stateless(name = UserManagerIf.JNDI_NAME) @Local(UserManagerIf.class) public class UserManager implements UserManagerIf { // Manager class data fields @PersistenceContext(unitName = UserBci.MANAGER_NAME) public EntityManager m_manager = null; private String m_findByLastName = "SELECT * FROM USERTABLE WHERE USERNAME = ? ORDER BY LASTNAME"; private String m_findByName = "select o from UserEntity o where o.userName = :name"; private String m_SQL_FIND_ALL = "select o from UserEntity o"; private String m_demoUserFunction = "select rawtohex(sys_guid()) from dual"; private String m_countUserTyp9 = "select count(o) from UserEntity o"; @EJB private ProductManagerIf m_ProductManagerIf = null; // Manager class methods /** * Manager method "findByLastName()" * @param name * @param level * @return * @throws PersistenceException */ public List<FindByLastNameData> findByLastName(String name, int level) throws PersistenceException { try { List<FindByLastNameData> list = null; List<?> entityList = m_manager.createNativeQuery(m_findByLastName,"findByLastName").setParameter(1,name).getResultList(); if(entityList != null && entityList.size() > 0) { list = new ArrayList<FindByLastNameData>(); for(Object entity : entityList) { if(entity != null) { FindByLastNameData data = new FindByLastNameData(); if(entity instanceof UserEntity) { data.setUser(((UserEntity)entity).callUser(level)); } list.add(data); } } } return list; } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } TLGen 169 StarData Gmb V 2.8 /** * Manager method "update()" * @param arg * @return * @throws PersistenceException */ public void update(UserData arg) throws PersistenceException { try { UserEntity entity = new UserEntity(); if(entity != null) { entity.updateUser(arg); m_manager.merge(entity); } } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Manager method "findByName()" * @param name * @param level * @return * @throws PersistenceException */ public UserData[] findByName(String name, int level) throws PersistenceException { try { UserData[] arrayData = null; List<?> list = m_manager.createQuery(m_findByName).setParameter("name",name).getResultList(); if(list != null && list.size() > 0) { arrayData = new UserData[list.size()]; int idx = 0; for(Object entity : list) { if(entity != null) { arrayData[idx++] = ((UserEntity)entity).callUser(level); } } } return arrayData; } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Manager method "detach()" * @param arg * @return * @throws PersistenceException */ public void detach(UserData arg) throws PersistenceException { try { UserEntity entity = getEntityByPrimaryKey(arg); if(entity != null && m_manager.contains(entity)) { m_manager.detach(entity); } } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Manager method "remove()" * @param arg * @return * @throws PersistenceException */ public void remove(UserData arg) throws PersistenceException { try { UserEntity entity = getEntityByPrimaryKey(arg); if(entity != null) { m_manager.remove(entity); } } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } TLGen 170 StarData Gmb V 2.8 } /** * Manager method "findAll()" * @param from * @param to * @param level * @return * @throws PersistenceException */ public UserData[] findAll(int from, int to, int level) throws PersistenceException { try { UserData[] listData = null; List<?> list = m_manager.createQuery(m_SQL_FIND_ALL).setFirstResult(from).setMaxResults(to).getResultList(); if(list != null && list.size() > 0) { listData = new UserData[list.size()]; int idx = 0; for(Object entity : list) { if(entity != null) { listData[idx++] = ((UserEntity)entity).callUser(level); } } } return listData; } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Manager method "findByPrimaryKey()" * @param arg * @param level * @return * @throws PersistenceException */ public UserData findByPrimaryKey(UserData arg, int level) throws PersistenceException { try { UserData classData = null; UserEntity entity = m_manager.find(UserEntity.class, arg.getUserID()); if(entity != null) { classData = entity.callUser(level); } return classData; } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Manager method "demoUserFunction()" * @throws PersistenceException */ public List<Object> demoUserFunction() throws PersistenceException { try { List<Object> listData = null; List<?> list = m_manager.createNativeQuery(m_demoUserFunction).getResultList(); if(list != null && list.size() > 0) { listData = new ArrayList<Object>(); for(Object object : list) { if(object != null) { listData.add(object); } } } return listData; } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Manager method "create()" * @param arg * @return * @throws PersistenceException */ TLGen 171 StarData Gmb V 2.8 public UserData create(UserData arg) throws PersistenceException { try { UserEntity entity = new UserEntity(arg); m_manager.persist(entity); return entity.callUser(99); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Manager method "getManager()" * @throws PersistenceException */ public UserManagerIf getManager() throws PersistenceException { try { return (UserManagerIf)ServiceLocator.getInstance().getLocalReference(UserManagerIf.class); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Manager method "close()" * @throws PersistenceException */ public void close() throws PersistenceException { try { m_manager.close(); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Manager method "clear()" * @throws PersistenceException */ public void clear() throws PersistenceException { try { m_manager.clear(); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Manager method "countUserTyp9()" * @throws PersistenceException */ public List<Object> countUserTyp9() throws PersistenceException { try { List<Object> listData = null; List<?> list = m_manager.createQuery(m_countUserTyp9).getResultList(); if(list != null && list.size() > 0) { listData = new ArrayList<Object>(); for(Object object : list) { if(object != null) { listData.add(object); } } } return listData; } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Manager method "readUpdate()" * @param arg * @return * @throws PersistenceException */ public void readUpdate(UserData arg) throws PersistenceException { try { UserEntity entity = getEntityByPrimaryKey(arg); TLGen 172 StarData Gmb V 2.8 } if(entity != null) { entity.updateUser(arg); m_manager.merge(entity); } } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } /** * Manager method "flush()" * @throws PersistenceException */ public void flush() throws PersistenceException { try { m_manager.flush(); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Manager method "getEntityByPrimaryKey()" * @param arg * @return * @throws PersistenceException */ public UserEntity getEntityByPrimaryKey(UserData arg) throws PersistenceException { try { UserEntity entity = m_manager.find(UserEntity.class, arg.getUserID()); return entity; } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Manager method "fullUpdate()" * @param arg * @return * @throws PersistenceException */ public void fullUpdate(UserData arg) throws PersistenceException { try { UserEntity entity = new UserEntity(); if(entity != null) { entity.updateUser(arg); entity.addUser(); m_manager.merge(entity); } } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Manager method "countUserTyp11()" * @param name * @return * @throws PersistenceException */ public Long countUserTyp11(String name) throws PersistenceException { try { UserCriteria criteria = new UserCriteria(); return criteria.countUserTyp11(m_manager, name); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Manager method "getEntityManager()" * @return */ public EntityManager getEntityManager() { return m_manager; } TLGen 173 StarData Gmb V 2.8 } 7.6.2 Entity Manager Bean Interface /** * **** do not change with a file editor ***** */ package eu.stardata.demo.server.persistence.user.managerif; import javax.persistence.EntityManager; import eu.stardata.demo.server.persistence.user.entity.UserEntity; import eu.stardata.demo.business.user.FindByLastNameData; import eu.stardata.demo.server.persistence.user.managerif.UserManagerIf; import java.lang.String; import eu.stardata.demo.business.user.UserData; import com.tlgen.common.exception.PersistenceException; import java.util.List; /** * This is a generate package for 'user' * * This is a interface for a entity manager. */ public interface UserManagerIf { // Manager interface data fields public String JNDI_NAME = "eu.stardata.demo.server.persistence.user.managerif.UserManagerIf"; public String EAR_NAME = "demo"; // Manager interface methods public List<FindByLastNameData> findByLastName(String name, int level) throws PersistenceException; public void update(UserData arg) throws PersistenceException; public UserData[] findByName(String name, int level) throws PersistenceException; public void detach(UserData arg) throws PersistenceException; public void remove(UserData arg) throws PersistenceException; public UserData[] findAll(int from, int to, int level) throws PersistenceException; public UserData findByPrimaryKey(UserData arg, int level) throws PersistenceException; public List<Object> demoUserFunction() throws PersistenceException; public UserData create(UserData arg) throws PersistenceException; public UserManagerIf getManager() throws PersistenceException; public void close() throws PersistenceException; public void clear() throws PersistenceException; public List<Object> countUserTyp9() throws PersistenceException; public void readUpdate(UserData arg) throws PersistenceException; public void flush() throws PersistenceException; public UserEntity getEntityByPrimaryKey(UserData arg) throws PersistenceException; public void fullUpdate(UserData arg) throws PersistenceException; public Long countUserTyp11(String name) throws PersistenceException; public EntityManager getEntityManager() ; } TLGen 174 StarData Gmb V 2.8 7.7 Entity Bean /** * **** do not change with a file editor ***** */ package eu.stardata.demo.server.persistence.user.entity; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.Table; import javax.persistence.Version; import org.hibernate.annotations.GenericGenerator; import eu.stardata.demo.business.user.UserData; import eu.stardata.demo.business.user.UserRoleData; import eu.stardata.demo.server.persistence.product.entity.ProductEntity; /** * This is a generate package for 'user' * * An entity is a lightweight persistence domain object. * Typically, an entity represents a table in a relational database, * and each entity instance corresponds to a row in that table. */ @Entity @Table(name="UserTable",uniqueConstraints = {}) @GenericGenerator(name="SEQ_STORE_USER", strategy = "sequence", parameters = {@org.hibernate.annotations.Parameter(name = "sequence", value = "USERTABLE_USERTABLE_ID_1SQ")}) public class UserEntity implements Serializable { private static final long serialVersionUID = 47812459; // Entity data field private UserData m_user = null; // Fields from relations tables private List<ProductEntity> m_product = new ArrayList<ProductEntity>(); private List<UserRoleEntity> m_userRole = new ArrayList<UserRoleEntity>(); // constructors /** * Default Constructor */ public UserEntity() { } /** * Constructor * @param arg */ public UserEntity(UserData arg) { m_user = arg; fillUser(); addUser(); } /** * Helper Method "setUser()" */ public void setUser(UserData arg) { m_user = arg; } TLGen 175 StarData Gmb V 2.8 // Helper methods /** * Helper Method "makeUser()" */ public UserData makeUser() { if(m_user == null) { m_user = new eu.stardata.demo.business.user.UserData(); } return m_user; } /** * Helper Method "updateUser()", used for update data in the database, * for relations "one to many" and "one to one" */ public void updateUser(UserData arg) { m_user = arg; fillUser(); } /** * Helper Method "fillUser()" */ public void fillUser() { // Relation ManyToMany, save data for "User" child, "UserRole" if(makeUser().getUserRole() != null) { for(UserRoleData dataif : makeUser().getUserRole()) { UserRoleEntity entity = new UserRoleEntity(dataif); m_userRole.add(entity); } } } /** * Helper Method "addUser()", used for create new objects in database, * for relations "one to many" and "one to one" */ public void addUser() { } /** * Helper Method "callUser()", used for read objects from the database, * for relations "one to many", "one to one" and "many to one" */ public UserData callUser(int level) { if(level > 0) { // Relation ManyToMany, save "UserRole" data object, in "User" object if(m_userRole != null) { List<UserRoleData> list1 = new ArrayList<UserRoleData>(); for(UserRoleEntity entity : m_userRole) { if(entity != null) { UserRoleData data = entity.callUserRole(level - 1); list1.add(data); } } makeUser().setUserRole(list1); } } // return the data object return makeUser(); } // Methods from columns @Id @Column(name = "UserTable_ID", nullable = false) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_STORE_USER") public long getUserID() { return makeUser().getUserID(); } public void setUserID(long arg) { makeUser().setUserID(arg); } TLGen 176 StarData Gmb V 2.8 @Column(name = "EJB3_OPTLOCK") @Version public long getEjb3Optlock() { return makeUser().getEjb3Optlock(); } public void setEjb3Optlock(long arg) { makeUser().setEjb3Optlock(arg); } @Column(name = "MODIFY_DATE") public Date getModifyDate() { return makeUser().getModifyDate(); } public void setModifyDate(Date arg) { makeUser().setModifyDate(arg); } @Column(name = "Email", length = 512) public String getEmail() { return makeUser().getEmail(); } public void setEmail(String arg) { makeUser().setEmail(arg); } @Column(name = "FirstName", length = 255) public String getFirstName() { return makeUser().getFirstName(); } public void setFirstName(String arg) { makeUser().setFirstName(arg); } @Column(name = "LastName", length = 255) public String getLastName() { return makeUser().getLastName(); } public void setLastName(String arg) { makeUser().setLastName(arg); } @Column(name = "UserName", length = 24, nullable = false) public String getUserName() { return makeUser().getUserName(); } public void setUserName(String arg) { makeUser().setUserName(arg); } @Column(name = "PassWord", length = 24, nullable = false) public String getPassWord() { return makeUser().getPassWord(); } public void setPassWord(String arg) { makeUser().setPassWord(arg); } // Methods from relations tables @ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE},mappedBy = "user",targetEntity = ProductEntity.class) public List<ProductEntity> getProduct() { return m_product; } public void setProduct(List<ProductEntity> arg) { m_product = arg; } @ManyToMany(targetEntity = UserRoleEntity.class) TLGen 177 StarData Gmb V 2.8 @JoinTable(name = "UserRole_UserTable",inverseJoinColumns = {@JoinColumn(name = "UserRole_ID",insertable = true, updatable = true, nullable = true, unique = false)},joinColumns = {@JoinColumn(name = "UserTable_ID",insertable = true, updatable = true, nullable = true, unique = false)}) public List<UserRoleEntity> getUserRole() { return m_userRole; } public void setUserRole(List<UserRoleEntity> arg) { m_userRole = arg; } } 7.8 Interceptor-Klasse /** * **** do not change with a file editor ***** */ package eu.stardata.demo.server.persistence.user; import javax.interceptor.AroundInvoke; import javax.interceptor.InvocationContext; import com.tlgen.common.exception.PersistenceException; /** * This is a generate package for 'user' * * Interceptors are used in conjunction with Java EE managed classes */ public class TimeCore { // Session annotations and fields for interceptor /** * Default Constructor */ public TimeCore() { super(); } // Session class methods /** * Interceptor method "timeTrace()" * @param invocation * @return * @throws PersistenceException */ @AroundInvoke public java.lang.Object timeTrace(InvocationContext invocation) throws PersistenceException { long start = 0; boolean toTime = true; try { if(toTime) { start = System.currentTimeMillis(); } return invocation.proceed(); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex,1); } finally { if(toTime) { // Example to time long ende = System.currentTimeMillis(); String klasse = invocation.getTarget().toString(); String methode = invocation.getMethod().getName(); System.out.println(klasse + ":" + methode + " -> " + (ende - start) + "ms"); TLGen 178 StarData Gmb V 2.8 } } } } 7.9 Timerservice-Klasse /** * This is a generated file by TLGEN. * Do not change it with a file editor. * * Version 2.8.002 */ //====================================================================== package eu.stardata.server.service.monitor; import java.util.Date; import javax.annotation.Resource; import javax.ejb.Remote; import javax.ejb.Stateless; import javax.ejb.Timeout; import javax.ejb.Timer; import javax.ejb.TimerService; import javax.inject.Inject; import com.tlgen.common.exception.PersistenceException; import eu.stardata.client.bci.monitor.MonitorBci; import eu.stardata.client.monitor.CallBackServiceMonitorIf; /** * This is a generate file * Service timer test for Monitor * * This is a timer service class */ @Stateless(name = MonitorBci.JNDI_NAME, mappedName = "efp/"+MonitorBci.JNDI_NAME+"/remote") @Remote(MonitorBci.class) public class MonitorSessionBean implements MonitorBci { // Session annotations and fields for timer service @Resource private TimerService m_timerService; private static final String KOMMAND = "TLG"; @Inject private CallBackServiceMonitorIf m_callBack; // Session class methods /** * Timer service method "initMonitor()" * @param start * @param stop * @param repeat * @return * @throws PersistenceException */ public void initMonitor(Date start, Date stop, long repeat) throws PersistenceException { try { // time to start and repeat timer service m_timerService.createTimer(start,repeat,KOMMAND); // time to stop timer service m_timerService.createTimer(stop,KOMMAND); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } TLGen 179 StarData Gmb V 2.8 } /** * Timer service method "stopMonitor()" */ public void stopMonitor() { for(Object obj : m_timerService.getTimers()) { Timer timer = (Timer)obj; String command = (String)timer.getInfo(); if(command.equals(KOMMAND)) { timer.cancel(); } } } } /** * Timer service method "timeoutMonitor()" * @param timer * @return */ @Timeout public void timeoutMonitor(Timer timer) { String command = (String)timer.getInfo(); if(command.equals(KOMMAND)) { m_callBack.checkEmails(this); } } 7.10 Web Service /** * **** do not change with a file editor ***** */ package eu.stardata.demo.server.persistence.soap; import java.util.List; import javax.ejb.Remote; import javax.ejb.Stateless; import javax.inject.Inject; import javax.jws.Web Service; import com.tlgen.common.ejb.session.BaseSessionBean; import com.tlgen.common.exception.PersistenceException; import eu.stardata.demo.business.user.UserData; import eu.stardata.demo.client.bci.soap.SoapBci; /** * This is a generate package for 'soap' for a Web Service */ @Stateless(name = SoapBci.JNDI_NAME, mappedName = "demo/"+SoapBci.JNDI_NAME+"/remote") @Remote(SoapBci.class) @Web Service(endpointInterface = "eu.stardata.demo.client.bci.soap.SoapBci", serviceName = "SoapSessionBeanService") public class SoapSessionBean extends BaseSessionBean implements SoapBci { // Session annotations and fields for local manager @Inject private CallBackWeb ServiceUserIf m_callBack; /** * Default Constructor */ public SoapSessionBean() { super(); } TLGen 180 StarData Gmb V 2.8 // Session class methods /** * Session method "updateUser()" * @param user * @return * @throws PersistenceException */ public UserData updateUser(UserData user) throws PersistenceException { try { return m_callBack.updateUser(user); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } /** * Session method "retrieveUser()" * @param name * @return * @throws PersistenceException */ public List<UserData> retrieveUser(String name) throws PersistenceException { try { return m_callBack.retrieveUser(name); } catch(Exception ex) { throw new PersistenceException(ex.getMessage(),ex); } } } 7.11 REST-Klassen 7.11.1 Client Seite /** * **** do not change with a file editor ***** */ package eu.stardata.test.rest; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.lang.reflect.Type; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; import java.text.DateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import junit.framework.TestCase; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import com.tlgen.common.rest.TlgListResponse; import eu.stardata.demo.business.user.UserJSon; import eu.stardata.demo.business.user.UserRoleJSon; /** * This is a transient file * Session bean is a web service session bean for REST * * This is a test class derived from a JUnit, * and is used to simplified the program develop and testing. * This class is to changed. TLGen 181 StarData Gmb V 2.8 */ public class TestRestUser extends TestCase { // Test class data fields private final static int TIMEOUT = 30000; private final static String CHARSET = "UTF-8"; private final static String REQ_PROP_CHARSET = "Accept-Charset"; private final static String REQ_PROP_CONTENT = "Content-Type"; private final static String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; /** * Default Constructor */ public TestRestUser() { super(); } // Test class methods /** * Test method "getHttpClient()" * @param type * @param strURL * @param contenttype * @param value * @return */ protected java.lang.String getHttpClient(String type, String strURL, String contenttype, String value) { if(strURL != null && type != null) { try { URL url = new URL(strURL); HttpURLConnection httpConnnection = (HttpURLConnection)url.openConnection(); httpConnnection.setDoOutput(true); // set request method type: GET, POST, PUT, DELETE for REST and , HEAD, OPTIONS, TRACE httpConnnection.setRequestMethod(type); httpConnnection.setReadTimeout(TIMEOUT); httpConnnection.setRequestProperty(REQ_PROP_CHARSET,CHARSET); // set the contenttype if(contenttype != null) { httpConnnection.setRequestProperty(REQ_PROP_CONTENT,contenttype); } if(type.equalsIgnoreCase("DELETE")) { httpConnnection.connect(); } // set the content else if(value != null) { // get the output stream writer and write the output to the server OutputStreamWriter out = new OutputStreamWriter(httpConnnection.getOutputStream()); out.write(value); out.close(); } // read the response result from the server BufferedReader reader = new BufferedReader(new InputStreamReader(httpConnnection.getInputStream())); String line = null; while((line = reader.readLine()) != null) { return line; } } catch (MalformedURLException e) { e.printStackTrace(); } catch (ProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); TLGen 182 StarData Gmb V 2.8 } } return null; } /** * Test method "testcreateUser()" */ public void testcreateUser() { try { System.out.println("----------- testcreateUser() -----------"); // Initialise input parameters Gson gson0 = new GsonBuilder().setDateFormat(DATE_FORMAT).create(); UserJSon json0 = new UserJSon(); json0.setEmail("[email protected]"); json0.setPassWord("xyz"); json0.setFirstName("Cris"); json0.setUserName("user03"); json0.setLastName("Smith"); json0.setModifyDate(new Date(System.currentTimeMillis())); fill the values for methods json0.setProduct(eu.stardata.demo.business.product.ProductJSon); UserRoleJSon role = new UserRoleJSon(); role.setUserRoleID(2L); List<UserRoleJSon> list = new ArrayList<UserRoleJSon>(); list.add(role); json0.setUserRole(list); String strJSon = gson0.toJson(json0); // // // REST call String strResponse = this.getHttpClient("POST","http://localhost:8080/rest/restApp/restSession/createUser","application/json",strJSon); // print return data if(strResponse != null) { System.out.println("strResponse :" + strResponse); Type responseType = new TypeToken<UserJSon>(){}.getType(); UserJSon response = gson0.fromJson(strResponse, responseType); if(response != null) { System.out.println("Ejb3Optlock :" + response.getEjb3Optlock()); System.out.println("Email :" + response.getEmail()); System.out.println("PassWord :" + response.getPassWord()); System.out.println("FirstName :" + response.getFirstName()); System.out.println("UserID :" + response.getUserID()); System.out.println("UserName :" + response.getUserName()); System.out.println("LastName :" + response.getLastName()); System.out.println("ModifyDate :" + response.getModifyDate()); if(response.getUserRole() != null) { for(UserRoleJSon arg : response.getUserRole()) { if(arg != null) { System.out.println(" RoleName :" + arg.getRoleName()); System.out.println(" Ejb3Optlock :" + arg.getEjb3Optlock()); System.out.println(" UserRoleID :" + arg.getUserRoleID()); System.out.println(" Description :" + arg.getDescription()); System.out.println(" ModifyDate :" + arg.getModifyDate()); } } } } } else { System.out.println("ReturnObject is null !!!"); } } catch(Exception ex) { ex.printStackTrace(); } } TLGen 183 StarData Gmb V 2.8 /** * Test method "testfetchUser()" */ public void testfetchUser() { try { System.out.println("----------- testfetchUser() -----------"); strContent,"application/json",null); // REST call String strContent = "/yyy-01"; String strResponse = this.getHttpClient("GET","http://localhost:8080/rest/restApp/restSession/fetchUser" + // print return data if(strResponse != null) { System.out.println("Response :" + strResponse); // make the response type Type responseType = new TypeToken<TlgListResponse<UserJSon>>(){}.getType(); // deserialize the response object Gson gson = new GsonBuilder().setDateFormat(DateFormat.LONG).create(); TlgListResponse<UserJSon> response = gson.fromJson(strResponse, responseType); if(response != null && response.getResult() != null) { for(UserJSon object : response.getResult()) { System.out.println("Ejb3Optlock :" + object.getEjb3Optlock()); System.out.println("Email :" + object.getEmail()); System.out.println("PassWord :" + object.getPassWord()); System.out.println("FirstName :" + object.getFirstName()); System.out.println("UserID :" + object.getUserID()); System.out.println("UserName :" + object.getUserName()); System.out.println("LastName :" + object.getLastName()); System.out.println("ModifyDate :" + object.getModifyDate()); System.out.println("Product :" + object.getProduct()); if(object.getUserRole() != null) { for(UserRoleJSon arg : object.getUserRole()) { if(arg != null) { System.out.println(" RoleName :" + arg.getRoleName()); System.out.println(" Ejb3Optlock :" + arg.getEjb3Optlock()); System.out.println(" UserRoleID :" + arg.getUserRoleID()); System.out.println(" Description :" + arg.getDescription()); System.out.println(" ModifyDate :" + arg.getModifyDate()); } } } } } } else { } System.out.println("ReturnObject is null !!!"); } } catch(Exception ex) { ex.printStackTrace(); } /** * Test method "testcountUsers()" */ public void testcountUsers() { try { System.out.println("----------- testcountUsers() -----------"); TLGen 184 StarData Gmb V 2.8 String strContent = "?name=xxx-01"; // REST call String strResponse = this.getHttpClient("GET","http://localhost:8080/rest/restApp/restSession/countUsers" + strContent,"application/json",null); // print return data if(strResponse != null) { System.out.println("strResponse :" + strResponse); } else { System.out.println("ReturnObject is null !!!"); } } catch(Exception ex) { ex.printStackTrace(); } } /** * Test method "testdeleteUser()" */ public void testdeleteUser() { try { System.out.println("----------- testdeleteUser() -----------"); // REST call String strContent = "/4"; String strResponse = this.getHttpClient("DELETE","http://localhost:8080/rest/restApp/restSession/deleteUser" + strContent,"application/x-www-form-urlencoded",null); } // print return data if(strResponse != null) { System.out.println("strResponse :" + strResponse); } else { System.out.println("ReturnObject is null !!!"); } } catch(Exception ex) { ex.printStackTrace(); } /** * Test method "testupdateUser()" */ public void testupdateUser() { try { System.out.println("----------- testupdateUser() -----------"); Gson gson0 = new GsonBuilder().setDateFormat(DATE_FORMAT).create(); UserJSon json0 = new UserJSon(); json0.setUserID(3L); json0.setEmail("[email protected]"); json0.setPassWord("xyz-abc"); json0.setFirstName("John"); json0.setUserName("user-update"); json0.setLastName("Johnson"); json0.setModifyDate(new Date(System.currentTimeMillis())); UserRoleJSon role = new UserRoleJSon(); role.setUserRoleID(2L); List<UserRoleJSon> list = new ArrayList<UserRoleJSon>(); list.add(role); json0.setUserRole(list); String strJSon = gson0.toJson(json0); // REST call TLGen 185 StarData Gmb V 2.8 String strResponse = this.getHttpClient("PUT","http://localhost:8080/rest/restApp/restSession/updateUser","application/json",strJSon); // print return data if(strResponse != null) { System.out.println("strResponse :" + strResponse); } else { System.out.println("ReturnObject is null !!!"); } } catch(Exception ex) { ex.printStackTrace(); } } } 7.11.2 Server Seite Für Interface siehe 7.5.4 /** * **** do not change with a file editor ***** */ package eu.stardata.demo.server.persistence.rest; import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.Stateless; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import org.jboss.resteasy.annotations.cache.NoCache; import com.tlgen.common.ejb.session.BaseSessionBean; import com.tlgen.common.rest.TlgListResponse; import eu.stardata.demo.business.user.UserJSon; import eu.stardata.demo.server.rest.CallBackRest; /** * This is a transient file * Session bean is a web service session bean for REST * * A session bean encapsulates business logic that can be invoked programmatically * by a client over local, remote, or web service client views. */ @Stateless(name = RestSession.JNDI_NAME) @LocalBean @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) @NoCache public class RestSessionBean extends BaseSessionBean implements RestSession { // Session annotations and fields for local manager @EJB private CallBackRest m_callBack; /** * Default Constructor */ public RestSessionBean() { super(); } // Session class methods /** * Session method "fetchUser()" TLGen 186 StarData Gmb V 2.8 * @param name * @return * @throws Exception */ public TlgListResponse<UserJSon> fetchUser(String name) throws Exception { try { return m_callBack.fetchUser(name); } catch(Exception ex) { throw new Exception(ex.getMessage(),ex); } } /** * Session method "createUser()" * @param user * @return * @throws Exception */ public UserJSon createUser(UserJSon user) throws Exception { try { return m_callBack.createUser(user); } catch(Exception ex) { throw new Exception(ex.getMessage(),ex); } } /** * Session method "countUsers()" * @param name * @return * @throws Exception */ public long countUsers(String name) throws Exception { try { return m_callBack.countUsers(name); } catch(Exception ex) { throw new Exception(ex.getMessage(),ex); } } /** * Session method "deleteUser()" * @param userId * @return * @throws Exception */ public String deleteUser(long userId) throws Exception { try { return m_callBack.deleteUser(userId); } catch(Exception ex) { throw new Exception(ex.getMessage(),ex); } } /** * Session method "updateUser()" * @param user * @return * @throws Exception */ public UserJSon updateUser(UserJSon user) throws Exception { try { return m_callBack.updateUser(user); } catch(Exception ex) { throw new Exception(ex.getMessage(),ex); } } } 7.12 Message Driven Bean package eu.stardata.server.message.chat; TLGen 187 StarData Gmb V 2.8 import javax.annotation.Resource; import javax.jms.Message; import javax.jms.JMSException; import javax.jms.ConnectionFactory; import javax.jms.ObjectMessage; import javax.ejb.ActivationConfigProperty; import javax.jms.BytesMessage; import javax.jms.Connection; import com.tlgen.common.ejb.message.BaseMessageBean; import eu.stardata.client.test.CallBackServerMessage; import javax.jms.MessageProducer; import javax.jms.TextMessage; import javax.jms.Session; import javax.jms.Topic; import java.io.Serializable; import javax.jms.MessageListener; import javax.ejb.MessageDriven; @MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/queueA"), @ActivationConfigProperty(propertyName = "messageSelector", propertyValue = "MessageFormat = 'TestMessage'"), @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"), @ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "NonDurable")}) public class TestMessageBean extends BaseMessageBean implements MessageListener { private static final long serialVersionUID = 73342617; // Manager class data fields @Resource(mappedName = "ConnectionFactory") public ConnectionFactory m_factory = null; @Resource(mappedName = "topic/topicA") public Topic m_connect = null; // Message class methods /** * Message method "onMessage()" * @param message * @return */ public void onMessage(Message message) { try { CallBackServerMessage callBack = new CallBackServerMessage(); Object backObject = callBack.callBackChat(message); // send back to the client the result from the call back class if(m_factory != null && m_connect != null) { Connection connect = m_factory.createConnection(); Session session = connect.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer sender = session. createProducer(m_connect); // make message receive object if(backObject instanceof String) { TextMessage textMessage = session. createTextMessage(); textMessage.setText((String)backObject); sender.send(textMessage); } else if(backObject instanceof byte[]) { BytesMessage bytesMessage = session. createBytesMessage(); bytesMessage.writeBytes((byte[])backObject); sender.send(bytesMessage); } else { ObjectMessage objMessage = session. createObjectMessage(); objMessage.setObject((Serializable)backObject); TLGen 188 StarData Gmb V 2.8 sender.send(objMessage); } connect.close(); } } } catch(JMSException ex) { ex.printStackTrace(); } } TLGen 189 StarData Gmb V 2.8 8 Vergleich zwischen TLGen und andere Code-Generatoren EJB (Enterprise Java Beans) sind standardisierte Komponente innerhalb eines Applikation Servers, mit dem Ziel, komplexe, mehrschichtige sowie verteilte Software Systeme mit der Programmiersprache Java zu vereinfachen. Die erste Spezifikation von EJB wurde von IBM im Jahr 1997 durchgeführt und von Sun Microsystems mit der Bezeichnung EJV 1.0 und 1.1 angenommen. Kurz danach erschienen die ersten Applikation Server „WebSphere“ von IBM und „WebLogic“ von BEA auf dem Markt. Das EJB-Konzept sollte die Softwareentwicklung von komplexen verteilten Applikationen stark vereinfachen. Das ist aber nur teilweise gelungen, da der persistente Teil (auf Basis von Entity Beans) erhebliche Performance-Verluste verbuchte. Aus diesem Grund sind eine Reihe von Applikationen als „Verbesserungs-Tools“ entwickelt worden, hauptsächlich um diesen Zustand, zu korrigieren. Version 2 von EJB verbessert diesen Zustand wesentlich, eine bessere Performance ist vorhanden. Aber geblieben ist eine gewisse Schwierigkeit durch sehr komplexe und aufwendig zu entwickelnde XML Dateien, notwendig für das Deployment von Applikation. Als Hilfe dafür ist das Tool „XDoclet“ gedacht, welches mit Hilfe von eigenen Tags relativ einfach diese komplexe XML Dateien generiert. Ab Version 3.0 und 3.1 von EJB sind alle Probleme von EJB sehr gut gelöst worden. Eine vernünftige Verwendung der Annotationen (neue Features von Java) lässt die komplette Generierung des notwendigen Java Codes, nur auf Basis von Domainmodell oder Datenmodell, zu. Die Generierungssteuerung (die nicht sehr umfangreich ist) übernimmt eine Konfigurationsdatei. Tools wie Hibernate sind für EJB 3 eigentlich nicht mehr notwendig, sie verkomplizieren sogar die gesamte Applikation. Diese Applikationen bergen folgende Nachteile: Die Applikation muss in der Running Zeit diese Tools in der Applikation einbeziehen: o das verkompliziert die Applikation o veranlasst eine Tool-Versions-Abhängigkeit sowie o Miteinbeziehung der Tool-Fehler Verwendet eine extra Code-Schicht als von EJB3 vorgesehen ist All diese Tools bringen nicht eine komplette neue Lösung in der Verwendung von Datenbanken mit sich, sondern sind nur eine Extraschicht für einen Applikation Server, um die Entwicklung mit allen diesen Nachteilen zu erleichtern. Eine reine Nutzung von EJB3 ohne zusätzliche Tools (wie z.B. Hibernate, Toplink, etc.) ist im direkten Vergleich zur Tool-Nutzung immer im Vorteil (siehe auch Anhang 1 - folgt in Kürze). Die Verwendung der Tools (wie z.B. Hibernate, TopLink, iBatis, etc.) mit einem EJB3 Applikation Server ist weder erforderlich noch empfehlenswert, es verkompliziert nur das IT-Programm ohne dabei Vorteile zu erbringen. So ein Tool ist nur für kleine Applikationen, die keinen Applikation Server benötigt, zu gebrauchen. TLGen 190 StarData Gmb V 2.8 In Gegensatz zu diesen Tools bringt TLGen durch eine komplette Generierung des notwendigen Java Codes eine wesentliche Vereinfachung in der Verwendung von EJB3, so dass sich die Entwicklung nur auf die Fachlogik einer Applikation konzentrieren kann. Die Verwendung von TLGen bringt folgende Vorteile: Komplette Code-Generierung: Test-Klassen, Client Technische-Klassen, Session Beans, Entity Manager, Entity Beans, „persistence.xml“ Dateien, DatenKlassen/Interfaces und Interceptor-Klassen. TLGen beteiligt sich nicht bei der Applikation in Running Zeit, d. h. keine Abhängigkeit von der TLGen Version. Der von TLGen generierte Code hat das gleiche Layout wie der Code, welcher ein Programmierer selber schreiben könnte. Durch die sofortige Code-Generierung mit Test-Klassen, können die Designer und Architekten die Ergebnisse von Konzepten sofort ersehen und eventuell optimieren (siehe Kap. 2). TLGen 191 StarData Gmb V 2.8 9 Literaturhinweis 1. “JSR 317: JavaTM Persistence API, Version 2.0”, EJB3 Persistence Specification 2. “JSR 318: Enterprise JavaBeansTM,Version 3.1” EJB3 Specification 3. “Enterprise JavaBeans 3.1 Eistig, Umstig, Paxis und Referenz” von Uwe Rozanski 4. „Java Web Services“ von Friedrich Kiltz 5. „Maven 3 Konfigurationsmanagement mit Java“ von Martin Spiller TLGen 192 StarData Gmb V 2.8 10 Glossar TLGen EJB REST SOAP Web Service Enterprise Java Beans Representational state transfer Simple Object Access Protocol Ist eine Methode zu Kommunizieren in „World Wide Web“ 193 StarData Gmb