Post on 29-Mar-2020
transcript
Thema 4 Acceleo- Sprachmittel und Generator- struktur
SE – Vertiefung Beuth-Hochschule Berlin
1. ACCELEO-PRAXIS
(c) schmiedecke 14 SE3 2
Abgeguckt bei Obeo UmlToJava
Es gibt zwei Generatorprojekte UmltoJava
UmlToJava (Helios)
einfach über den Marketplace installieren
(überschaubarer, hier überwiegend verwendet)
UmlToJava (Kepler)
über das Obeo-Network von Github herunterladen
(Anspruchsvoll, Projekt wird fortgeführt)
(c) schmiedecke 14 SE3 3
Templating-Sprache
Ein Generator besteht aus Templates
(+ Queries + Properties)
(mind.) ein Template wird als Main Template
ausgezeichnet
Die Ausgabe erfolgt in die Datei, die im File-Block
angegeben ist
Mehrere File-Blöcke sind möglich, aber nur nacheinander
(c) schmiedecke 14 SE3 4
Beispiel 1
[comment encoding = UTF-8 /]
[module generateUmlToJava('http://www.eclipse.org/uml2/4.0.0/UML')]
[template public generate(aClass : Class)]
[comment @main/]
[file (aClass.name.concat('.java'), false)]
public class [aClass.name.toUpperFirst()/] {
[for (p: Property | aClass.attribute) separator('\n')]
private [p.type.name/] [p.name/];
[/for]
[for (p: Property | aClass.attribute) separator('\n')]
public [p.type.name/] get[p.name.toUpperFirst()/]() {
return this.[p.name/];
}
[/for]
}
[/file]
[/template]
(c) schmiedecke 14 SE3 5
Beispiel 1a
[module generateJava('http://www.eclipse.org/uml2/3.0.0/UML')/]
[import common/]
[import interfaceBody/]
[import
org::eclipse::acceleo::module:.example::uml2java::helios::common::classBody/]
[template public generateClass(c : Class)]
[comment @main /]
[file (c.getFullPathFile().trim(), false)]
[_commentFileBlock()/]
[c.packageBlock()/]
[importBlock()/]
[_commentBodyBlock()/]
[c.generateClassBody()/]
[/file]
[/template]
(c) schmiedecke 14 SE3 6
Beispiel 1b – zweites Main Module und zweites File
[template public generateInterface(i : Interface)]
[comment @main /]
[file (i.getFullPathFile().trim(), false)]
[_commentFileBlock()/]
[i.packageBlock()/]
[importBlock()/]
[_commentBodyBlock()/]
[i.generateInterfaceBody()/]
[/file]
[/template]
[query public getJavaFileName (name : String) : String =
name.concat('.java')
/]
(c) schmiedecke 14 SE3 7
Templates - Details
Templates haben keinen Rückgabetyp,
sie erzeugen Output (String)
Templates haben Parameter,
die Typen sind Metamodell-Elemente
Ein Template-Aufruf wird nur ausgeführt, wenn der
Parameter "passt" (bzw. die Parameter passen)
Bei Anwendung auf eine Menge von Elementen wird
das Template wiederholt angewendet
(s. Folgefolie)
Templates realisieren Polymorphie
sie werden je nach Parameter-(Sub-)Typ ausgewählt
(s. Folgefolie) (c) schmiedecke 14 SE3 8
Beispiel 2a: Schleife und Typ-Switch Quelle: Acceleo Best Pracitces
[template public classSwitchTemplate(eClass : Eclass)
[for (eNamed : ENamendeElement | eClass .eAllContents(ENamedElement))]
[if (eNamed.oclIsKindOf(ETypedElement))]
do something for ETypedElement
[elseif (eNamed.oclIsKindOf(EStructuralFeature))]
do something for EStructuralFeature
[elseif (eNamed.oclIsKindOf(EAttribute))]
do something for Eattribute
[/if]
[/for]
[/template]
(c) schmiedecke 14 SE3 9
Beispiel 2b: Menge und Polymorphie
[template public polymorphicClassTemplate(eClass : EClass)]
[eClass.eAllContents(ENamedElement).doSomething()/]
[/template]
[template private doSomething(arg : ETypedElement)]
do something for ETypedElement
[/template]
[template private doSomething(arg : EStructuralFeature)]
do something for EStructuralFeature
[/template]
[template private doSomething(arg : EAttribute)]
do something for EAttribute
[/template]
[template private doSomething(arg : ENamedElement)] [/template]
(c) schmiedecke 14 SE3 10
Navigieren im Modell
Navigieren im Modell erfolgt anhand des Metamodells
Zu den Attributen
– liefert typischerweise einfache Werte [c.name/]
Über die Assoziationen des Metamodells
– liefert typischerweise Mengen!! [c.superClass/]
Über die Funktionen des EMF-GenModels
Über die Acceleo-Operationen auf EObject
– eAllContents
– eContainer
– ancestors
– siblings
– followingSiblings ...
(c) schmiedecke 14 SE3
11
Navigieren mithilfe des
EMF-GenModels der UML
(c) schmiedecke 14 SE3 12
Beispiel 3 – Navigieren im Modell
[template public generateClassBody(c : Class)]
public
[if (c.isAbstract)] abstract
[/if]
class [c.name.toUpperFirst()/]
[for (superC : Class | c.superClass) before(' extends ')
separator(',')] [superC.name/]
[/for]
[for (interf : Interface | c.getImplementedInterfaces()) before('
implements ') separator(',')] [interf.name/]
[/for]
(c) schmiedecke 14 SE3 13
...erreichbar über die Acceleo-Vorhersage
(c) schmiedecke 14 SE3 14
Beispiel 4
[for (p : Property | c.getAllAttributes())]
[if (p.upper = -1 or p.upper > 1)]
private List<[p.type.name/]> [p.name/];
[else]
private [p.type.name/] [p.name/];
[/if]
[/for]
(c) schmiedecke 14 SE3 15
Navigieren mithilfe des
EMF-Genmodels der UML
(c) schmiedecke 14 SE3 16
... erreichbar über die Acceleo-Vorhersage
(c) schmiedecke 14 SE3 17
Beispiel 5
[template public packagePath(cl : Classifier)]
[cl.getNearestPackage().normalizeName()/]
[/template]
(c) schmiedecke 14 SE3 18
Acceleo-
Operationen
wiki.eclipse/
Acceleo/
Acceleo_Operations
_Reference
(c) schmiedecke 14 SE3 19
Parametrisierte Operationen (Acceleo und Genmodel)
Die meisten mengenliefernden Acceleo-Operationen
können durch einen Parameter eingeschränkt werden
z.B.:
(c) schmiedecke 14 SE3 20
Beispiel 6 – Parametrisierte Operationen
[template public genPackagePath(anElement : Element)]
[if (anElement.ancestors(Component)->size() > 0)]
[anElement.ancestors(Component)
->first().genComponentPath()/]
[else][anElement.reqGetDefaultProjectName()/]
[/if]
/[anElement.reqGetSourceFolderPath()/]
/[anElement.genPackageDeclaration().substituteAll('.', '/').concat('/')/]
[/template]
(c) schmiedecke 14 SE3 21
Templates können eingeschränkt und mit post nachbearbeitet werden
(c) schmiedecke 14 SE3 22
"? (Bedingung)" im Template-Tag schränkt die
Gültigkeit ein
"post" ermöglicht abschließende Bearbeitung des
Outputs
Beispiel 7 – Template-Einschränkung
(c) schmiedecke 14 SE3 23
[template private getterAndSetter(aProperty : Property) ?
(aProperty.upper = 1)]
public [if(aProperty.isStatic)]
static
[/if]
[aProperty.reqTypeName()/]
get[aProperty.genName().toUpperFirst()/]()
{
return [if(not aProperty.isStatic)]this.[/if]
[aProperty.genName()/];
}
...
Beispiel 8 – Template-Nachbearbeitung
[template private normalizeName(anElement : NamedElement) post(trim())]
[if ((anElement.name = 'package') or (anElement.name = 'interface') or
(anElement.name = 'class'))]
[anElement.name.concat('_')/]
[else]
[anElement.name/]
[/if]
[/template]
(c) schmiedecke 14 SE3 24
Operationsanwendung
Operationen (Acceleo, EMF, OCL) werden angewendet
Mit "." auf einfache Werte
[anElement.genPackageDeclaration().substituteAll('.',
'/').concat('/')/]
Mit "->" auf Mengen und Folgen
[if (anElement.ancestors(Component)->size() > 0)]
(c) schmiedecke 14 SE3 25
Let-Blöcke
Mit dem let-Tag können Variablen mit der Gültigkeit
des Let-Blocks definiert werden
Der Let-Block wird nur dann ausgeführt, wenn die
Variablen-Zuweisung typkompatibel ist (also
"funktioniert")
[let x : Type = myExpression] | x.dosomething() [/let]
Ist gleichbedeutend mit
[if (myExpression.oclIsKindOf(Type))]
[myExpression.oclAsType(Type).dosomething()/]
[/if]
(c) schmiedecke 14 SE3 26
Beispiel 9 – Let-Block Wird nur ausgeführt, falls aClass einen Wert hat
[template private genClassifierBody(aClassifier : Classifier) overrides genClassifierBody]
[let aClass : Class = aClassifier.oclAsType(Class)]
[aClass.declaration()/] {
[aClass.attributes()/]
[aClass.constructor()/]
[aClass.operations()/]
[for (aProperty : Property | aClass.ownedAttribute
->union(aClass.reqOutgoingNavigableOwnedEnd()))]
[aProperty.accessors()/]
[/for]
[/let]
[/template]
(c) schmiedecke 14 SE3 27
Mengenkonstruktion
Die Navigation durch Metamodell liefert immer wieder
Mengen
Viele Acceleo- und OCL-Operationen dienen der
Bearbeitung von Mengen
– Filtern
– Vereinigen
– Zu Sequenzen machen – oder wieder zu Mengen
– Unterstrukturen auflösen (flatten)
Vieles lässt sich mit Mengenoperationen eleganter
ausdrücken als mit Schleifen ÜBEN
(c) schmiedecke 14 SE3 28
Beispiele 10 - Mengenoperationen
[template public genPackageDeclaration(anElement : Element)]
[anElement.packagePath().normalizeName()->reverse()->sep('.')/]
[/template]
[for (aParameter : Parameter | ownedParameter
->select(param : Parameter |
param.direction = ParameterDirectionKind::return)
->first())]
...
(c) schmiedecke 14 SE3 29
OCL-
Operationen
wiki.eclipse.org/Acceleo/
OCL_Operations
_Reference
Ähnlich wie Acceleo-Ops,
andere Typen
(c) schmiedecke 14 SE3 30
Queries
Queries sind Expressions, d.h. Sie liefern ein Ergebnis
Zweck: Kapselung / Wiederverwendung komplexer
Abfragen
++Ergebnis wird gecached (Effizienzgewinn)
Typischerweise, aber nicht zwingend, OCL
(c) schmiedecke 14 SE3 31
Beispiele 11
[query public getJavaFileName (name : String) : String =
name.concat('.java')
/]
[query private packagePath(anElement : Element) : Sequence(Package) =
Sequence{anElement.getNearestPackage()}
->union(anElement.getNearestPackage().ancestors()->filter(Package))
->select(pack : Package | pack.oclIsTypeOf(Package))
/]
[query private allDocumentation(anElement : Element) : Sequence(String) =
anElement.eAnnotations.details->select(entry | entry.key = 'documentation')
->collect(entry | entry.value)
/]
(c) schmiedecke 14 SE3 32
Queries als Java Wrapper Services
EMF liefert das Modell als Java-Objektbaum
und ein Traversierungs-API (GenModel)
Alle Abfragen lassen sich auch in Java formulieren
Dort, wo das leichter ist, kann Java-Code geschrieben
und innerhalb einer Query mit "invoke" gerufen werden
(s. Getting-Started-Tutorial)
(c) schmiedecke 14 SE3 33
Konstanten
Konstanten können als Property-Datei hinterlegt
werden
Syntax:
– Schlüssel = Text
(c) schmiedecke 14 SE3 34
ACCELEO –
BEST PRACTICES
(c) schmiedecke 14 SE3 35
Quellen
(c) schmiedecke 14 SE3
36
Best practices: Naming Conventions
A. Naming conventions
Project (eclipse plugin):
<domain><project name (optional)><kind of input
(optional)><input metamodel name>gen<output language
name>
Example: com.mydomain.myproject.pim.uml.gen.java
Modules, variables
camel case names, avoid acceleo or ocl keywords:
Acceleo keywords: module, import, extends, template, query,
public, private, protected, guard, init,overrides, each, before,
after, for, if, elseif, else, let, elselet, trace, macro,file, mode,
text_explicit, code_explicit, super, stdout
OCL keywords: and, body, context, def, derive, else, end, if,
endpackage, false, if, implies, in, init, inv, invalid, let, not, null,
or, package, post, pre, self, static, then, true, xor
(c) schmiedecke 14 SE3 37
BP: Package Structure
Root package should share the same name of the project.
Example: com.mydomain.myproject.pim.uml.gen.java
Subpackages
main
all modules with main templates and their matching launcher class
files
all modules that will generate a file
common
all utility modules
request / query
all modules that contains utility requests (queries) on the input model
services
all modules wrapping Java classes
properties
all properties files
(c) schmiedecke 14 SE3 38
BP: Package Structure
(c) schmiedecke 14 SE3 39
BP: Package Export
B. 3. Exporting packages
The main package, the properties package and the
service package need to be exported.
Java services will not work when the generator is
deployed if the package containing those package is
not exported in the MANIFEST.MF (runtime tab).
It is recommended to export all other packages but to
keep them "hidden from all plugins".
(c) schmiedecke 14 SE3 40
Der Rest ist ÜBEN
und ABGUCKEN...