Generative
Software
Engineering
3. Integrating Handwritten Code
Prof. Dr. Bernhard Rumpe Software Engineering RWTH Aachen University http://www.se-rwth.de/ Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 2
Not everything shall and can be generated
• Code is fine, when model would not be more abstract How to integrate hand written code with generated code
• General principles • How they apply in DEX
Generation and Handcoding
Parame-terized generator
Generator script/template Map: concept code
model
hand written code
runtime system
Environment: hardware, GUI, frameworks generated code + included parts Predefined componentsPredefined componentsPredefined components API API
Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 3
Goals of Handcoding
The goal of handcoding
• extend domain model
• add functionality to generated code
• customize generated code
Benefits of handcoding
• Normally re-generation is not needed
• Reuse of existing handwritten code
• Tooling (e.g. editor) for the programming language can be used
DEX supports extensions for
• domain model with attributes and method bodies • domain model with signatures
• generated GUI code
Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 4
Handwritten Code
Handcoding (HC) = the process of writing code manually (by hand)
vs. generating code (GC), where the code comes from the generator.
Important questions to decide:
• Artefacts of interest for users?
• What to write, what to read and understand
• Generating and handcoding in which order?
• Repeatable generation?
• Dependences between the forms of code? • Methodical alignment
• Which knowledge is necessary for
• the developer • the generating tool
Software Engineering RWTH Aachen
Page 5
Mixing of HC and Generation in Artifacts
Scenario A:
• 1. Let the generator produce code frames in files • 2. Add code manually, e.g. method implementations Advantage:
• HC is well integrated inside GC Disadvantage:
• “One shot” generation only
• Model becomes irrelevant because useless after generation, • Changes in models impossible
• Doesn’t support evolution Decision:
• Strict separation of handcoding and generation on artifacts! • Each artifact (= file) is either handcoded or generated.
Prof. Dr. B. Rumpe
Lehrstuhl für Software Engineering RWTH Aachen
Page 6
Mixing of HC and Generation in Artifacts -2
Scenario B:
• 1. Let the generator produce code frames in files
• Generate explicit markers to protect regions of HC
• 2. Add code manually in protected regions
Advantage:
• Easy to use and easy to identify where to handcode
Necessary:
• Extraction of HC for inclusion in next generation step
Disadvantages:
• Not robust e.g. against editing
• Vulnerable against advanced tools (e.g. beautifiers) • No clean full generation possible
• Generated code needs to be version controlled public class Person {
public String getFullname () {
/* [protected GEN#XwgHEge23qp (method getFullname)] */ // to be handcoded /* [/protected GEN#XwgHEge23qp] */ } } Java «hc» «gen» «gen»
Prof. Dr. B. Rumpe
Lehrstuhl für Software Engineering RWTH Aachen
Page 7
Separation of HC and GC in Artifacts
Each artifact (file) is either HC or GC.
Advantages:
• Only sources (HC and models) need to be versioned
• this greatly reduces conflicts
• and helps understanding progress from the version control logs
• Developers normally don’t read generated code
• just understand the interfaces
• Clean & regenerate always works Necessary:
• HC needs to be written and integrated
Prof. Dr. B. Rumpe
Lehrstuhl für Software Engineering RWTH Aachen
Page 8
Alternatives for Integration of HC
1. Reference it from the model. • Ch. 2 for attributes &
• DEX would allow method signatures & bodies in a CD, but that pollutes the CD (not recommended)
2. Compiler: no that doesn’t work
• We would need “partial classes”, not provided by Java
3. When starting at runtime
• 3a) Write your own main()-function and call HC to configure GC
• that is fine and actually used by many frameworks
• 3b) write static-code pieces: no, because classes are loaded lazy in Java (and thus static code may be never called)
4. Config file
• Works, but is error prone because it looses type safety.
5. Generator identifies HC and integrates references to it
Software Engineering RWTH Aachen
Page 9
Generated DEX product has this architecture
• HC internal architecture is out of generators control: • But it is recommended to maintain the architecture
Overview of Product with HC
RTE standard components Application Core RTE standard components GUI RTE standard components Persistence hand coded hand coded hand coded generated generated generated Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 10
Generator detects HC, the Principle:
Approaches DEX uses: (Placeholder X)
1. Extending signature and implementation of domain class X.java • When XSIG.java exists inherit it in X.java
• When XEIMP.java exists use it in the factory
(assuming it is a subclass of XIMP) 2. Specific Hot Spots documented in the generator handbook.
Extending signature, implementation and hot spots
Generative
Software
Engineering
3. Integrating Handwritten Code 3.1. Extension of Generated Code
Prof. Dr. Bernhard Rumpe Software Engineering RWTH Aachen University http://www.se-rwth.de/ Farbe! Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 12
Generated Artifacts in DEX
What DEX does:
One class is mapped to • an interface
• an implementation, and • a factory for object creation
GroupFactory
+static Group create() #Group doCreate() …
class Group extends Profile
{ // … String purpose; } CD SocNet Java «gen» «interface» Group + String getPurpose(); + void setPurpose(String s) … GroupImpl - String purpose; + String getPurpose(); + void setPurpose(String s) …
Software Engineering RWTH Aachen
Page 13
Extending the Implementation
… and adapting generated functionality
by defining HC class XEIMP that inherits GC
Generator adapts only the GroupFactory
• now GroupEIMP objects are created
Necessary:
• GroupEIMP is subclass of GroupImpl
• “EIMP” was chosen to prevent occasional use • “EIMP” = extended implementation
«interface» Group
GroupImpl
GroupEIMP
GroupFactory +static Group create() #Group doCreate() …
import GroupEIMP; …
class GroupFactory …
protected Group doCreate() { return new GroupEIMP(); }
handcoded Java class
adapted Factory Product-CD «hc» «gen» «gen» «gen» «gen» Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 14
Two steps are required to add handcoded Java classes in DEX • 1. Create handcoded Java class GroupEIMP
• 2. Implement the full and the empty constructor of GroupImpl
• (3. Override methods and add attributes/methods …)
public class GroupEIMP extends GroupImpl {
public GroupEIMP() {
super(); }
protected GroupEIMP(String profileName, boolean isOpen, Date created, String purpose) {
super(profileName, isOpen, created, purpose); }
}
How to add handcoded Java classes
attributes of class GroupImpl
Java «hc»
Prof. Dr. B. Rumpe
Lehrstuhl für Software Engineering RWTH Aachen
Page 15
The domain model can be extended by adding attributes
Properties of these attributes • not visible in the GUI • not saved in the database
public class GroupEIMP extends GroupImpl {
private String newAttribute = "My String";
// ... }
How to add attributes to the domain model
new domain model attribute Java «hc» Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 16
Application functionality can be extended by adding new methods • This brings the “meat” to the application
Limitations
• New methods do not appear in the signature of the Group interface
public class GroupEIMP extends GroupImpl { // ...
public String groupOverview (){
return "Group Overview: " + getPurpose() + " " + getHeadcount();
} }
How to add Methods
new method Java «hc»
Software Engineering RWTH Aachen
Page 17
How to implement derived Attributes
Derived attribute does have an empty default implementation as get/retrieve-method
Add meaning to the derived attribute using HC by overriding the getter
Every generated method can be overwritten • Incl. ordinary get/setters for attributes • Association methods
public class GroupEIMP extends GroupImpl { // ...
@Override
public int getHeadcount() {
return sizeMembers()+ sizeOrganizers(); } } Group /int headcount; … Java «hc» Model-CD Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 18
derived attributes are shown in the gui
Prof. Dr. B. Rumpe
Lehrstuhl für Software Engineering RWTH Aachen
Page 19
Overwriting Generated Methods
Generated methods can be adapted by HC
Log result is shown in the bottom line on the GUI
public class GroupEIMP extends GroupImpl { //constructors ...
public void setPurpose(String pname) {
StatusBar.write("Group "+profileName +" new purpose "+pname)
super.setPurpose(pname); } } Group boolean isOpen Date created String purpose /int headcount overrride Logging Java «hc» Model-CD Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 20
Extending the Implementation
Advantages:
• relatively little effort to adapt implementation
• adaptable reuse of generated implementation • smooth integration of HC artefact
Restriction:
• Only one subclass supported Disadvantages:
• IDEs don’t assist when superclass hasn’t been generated yet
• = many false errors are reported after fresh checkout or a clean
• some risk of unwanted occasional detection of “*EIMP”
• re-generation necessary after EIMP-class is created (or deleted) to get adapted factory
«interface» Group GroupImpl GroupEIMP Product-CD «hc» «gen» «gen»
Generative
Software
Engineering
3. Integrating Handwritten Code
3.2. Extending Data Model Signature
Prof. Dr. Bernhard Rumpe Software Engineering RWTH Aachen University http://www.se-rwth.de/ Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 22
by defining HC interface XSIG that inherits to GC
1. Generator detects XSIG.java
2. Generated code is adapted to implement the new interface
3. Generator also expects XEIMP.java, because XImpl is now abstract
Signature extensions (methods) are inherited to interface X.java and handcoded in XEIMP.java “Sandwich”-Principle for extension
Extending the Signature of a Class
public interface GroupSIG {
String getFullname(); } «interface» GroupSIG Product-CD «interface» Group GroupImpl GroupEIMP «hc» «gen» «gen» «hc»
Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 23 Required steps
• 1. Add handwritten Java interface XSIG
• 2. Add handwritten Java class XEIMP
• 3. Implement new methods in XEIMP
How to add signature extensions
public interface Group extends dex.socnet.GroupSIG { //... } handwritten Java interface «interface» GroupSIG Product-CD «interface» Group GroupImpl GroupEIMP «hc» «gen» «gen» «hc» Java «gen»
public abstract class GroupImpl implements dex.socnet.Group
{ //... } Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 24
Mapping Model Inheritance and HC Extension
Inheritance and implementation relation is preserved
DEIMP inherits CEIMP indirectly
through DImpl
interface A; interface B;
class C implements A;
class D extends C implements B;
Model-CD «interface» B DEIMP Product-CD «gen» «interface» A CEIMP «interface» DSIG «interface» C «interface» BSIG «interface» ASIG «abstract» DImpl «abstract» CImpl «interface» CSIG «interface» D
Software Engineering RWTH Aachen
Page 25
Advantages
• Separation of generated and handwritten artifacts
• Signature extensions in HC interfaces
• Supports redefinition of generated functionality
• Supports implementation of internally available methods and attributes
Disadvantages/problems
• Signature of methods need to be repeated at implementation • Re-generation is necessary when SIG/EIMP-class is added or
removed
Signature Extensions Summary
Generative
Software
Engineering
3. Integrating Handwritten Code 3.3. Hot Spots for the DEX GUI
Prof. Dr. Bernhard Rumpe Software Engineering RWTH Aachen University http://www.se-rwth.de/
Prof. Dr. B. Rumpe
Lehrstuhl für Software Engineering RWTH Aachen
Page 27
A hot spot is a place in the generated code that is planned for adaptation by handwritten code.
The adaptation is carried out through the generator detecting and including appropriate HC.
Hot spot documentation needs:
• A) How does a hot spot look like
• e.g. naming conventions for the class
• B) Signature the hot spot has to provide • C) What is the API the hot spot can use The approach is similar to framework hot spots.
Hot Spot
Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 28 Often the GUI of a DEX product needs adaptation
• More functions, more screens, nicer appearance, …
• GUI can be customized by adding handwritten extensions DEX has e.g. hot spots prepared for
• Menu Extension
• Home Screen Adaptation • Panel Extensions
• Startup and TearDown Phases
Adapting a hot spot needs some knowledge about the mechanisms of the adapted GUI.
Examples of DEX SocNet adaptations:
• see DEX website: http://www.monticore.de/dex/
Software Engineering RWTH Aachen
Page 29
Hot Spot: Menu Extension
public class MainWindowViewEIMP extends MainWindowView { //constructors
public void extendMenu() {
JideMenu m = new JideMenu("StatusBar"); JMenuItem item = new JMenuItem("print"); m.add(item);
item.addActionListener(new ActionListener() { @Override
public void actionPerformed(ActionEvent e) {
StatusBar.write("Menue item print was clicked");
}});
addMenuItem(m); }
}
Purpose: Add menu items
Hot spot class: MainWindowViewEIMP
Methods to override: • extendMenu() Available API: • addMenuItem(), … Java «hc» Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 30
How to Adapt the Home Screen
Purpose: Customize home screen
Hot spot class: MainWindowPresenterEIMP
Methods to override:
• setHomeTitle() Available API (see code):
• Swing
public class MainWindowPresenterEIMP extends MainWindowPresenter { //constructors
public JPanel setHomeTitle() { JPanel panel = new JPanel(); panel.setLayout(null);
JLabel lblSystem = new JLabel("SocNet System");
lblSystem.setHorizontalTextPosition(SwingConstants.CENTER); lblSystem.setHorizontalAlignment(SwingConstants.CENTER); lblSystem.setFont(new Font("Tahoma", Font.PLAIN, 40)); panel.setLayout(new BorderLayout(0, 0)); panel.add(lblSystem, BorderLayout.CENTER); return panel; } } Java «hc»
Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 31
Adapting Panels
Purpose: Customize Panel for Specific Domain Class “X”
Hot spot class: XEditPanelViewEIMP Methods to override:
• getXPanelComponent() Available API (see code):
• Swing
• Reusable: Methods from XEditPanelView
TagEditPanelView
«interface» ITagEditPanelView
TagEditPanelView
TagEditPanelViewEIMP
public class TagEditPanelViewEIMP extends TagEditPanelView { //constructors
public ITagPanelComponentView getTagPanelComponent() {
//... } } «hc» «gen» «gen» Java «hc» Product-CD Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 32
StartUp & TearDown
Purpose: Add startup and teardown actions or takeover control completely
Hot spot class: XControllerEIMP (for model X.cd)
Methods to override:
• startUp()
• tearDown()
Available API (see code):
• Reusable: Methods from AbstractController
public class SocNetControllerEIMP extends SocNetController{ //constructors
protected void startUp() {
//... some startUp actions }
protected void tearDown() {
//... some tearDown actions }
Software Engineering RWTH Aachen
Page 33
Summary – Lessons learned
Hot spots are HC classes that replace generated classes • and at the same time inherit their functionality for reuse Hot spots can be used for various purposes:
• Signature extension • Method overwriting • Functionality extension
Hot spots allow to inject HC into a generated system, thus adapting it for specific needs
Hot spots are filled during the generation process • and identified through naming conventions
Hot spots are usually model-specific
Generative
Software
Engineering
3. Integrating Handwritten Code 3.4. More Adaptation Mechanisms
Prof. Dr. Bernhard Rumpe Software Engineering RWTH Aachen University http://www.se-rwth.de/
Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 35
Class Overriding
The principle:• When X.java exists in handcoded form
just use it and generate nothing
Required:
• HC Java can be distinguished from GC
• e.g. disjoint directories for HC and GC
Advantage:
• Anything can easily be adapted Disadvantage:
• X.java: nothing is generated anymore; no reuse
• Brittle: adaptations of model need to be tracked manually in HC
Prof. Dr. B. Rumpe
Lehrstuhl für Software Engineering RWTH Aachen
Page 36
Class Overriding plus Prototypes
The principle:
• When X.java exists in handcoded form
use it, but generate XProto.java instead
• Xproto.java can be used as superclass for HC X.Java Advantage:
• Anything can easily be adapted
• Reuse of generated code possible, which is still there
Disadvantage:
• Brittle: adaptations of model need to be tracked manually in HC Remark: very similar to the Dex approach using EIMPL
Software Engineering RWTH Aachen
Page 37
Use GUI as Framework
The principle:
• The generated code may be adaptable by classic programming techniques, e.g. usable as framework
Required:
• Explicit hot spots (= empty methods) that can be overwritten in subclasses
• Possibilities to adapt / configure in the generated code Advantage:
• Traditional form of adaptation, no interaction with generator Disadvantage:
• Generated code needs to be a framework
Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 38
Delegation to HC
The principle:• The generated code uses delegation to hot spots
Similar to the used inheritance approach Advantage:
• More flexible, e.g. individual delegators for each method Disadvantage:
• More complex: more objects to manage, • Objects have substructure
delegate Delegation delegator delegate Person String getFullName() «interface» PersonDelegate String getFullName() Person String getFullName() PersonImpl String getFullName() Model-CD Product-CD «hc» «gen» «gen»
Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 39
Partial Classes
The principle:• The language allows classes to be distributed over several artefacts, called “partial classes”
Advantage:
• Generation of classes piecewise is possible
Disadvantage:
• Java doesn’t support this (It can be mimicked by a design pattern) • Generated functionality cannot be redefined
Model-CD partialstring firstName;class Person{
//… }
partial class Person{
public string getFullname(){ //… } } classes have the same names Person String firstName String getFullName() «hc» «gen» C# Prof. Dr. B. Rumpe Lehrstuhl für Software Engineering RWTH Aachen Page 40
Aspect Orientation for HC-Injection
The principle:
• Use an Aspect-Oriented Language • Add functionality in form of Aspects Disadvantage:
• From SE point of view aspects are harmful. Not recommended to use an AOP language for coding. (Much worse than goto)
public class Person { //… generated impl public void clearMembers() { //… default impl } }
public aspect PersonAspect {
pointcut pcClearMembers(Person p):
execution(* Person.
clearMembers()) && target(p);
void around(Person p): pcClearMembers (p) { // … handwritten impl } } AspectJ Handwritten impl. in advice p = instance on which method shall be executed Java «gen» «hc»
Software Engineering RWTH Aachen
Page 41
Embed Action Language in Model
The principle:
• Embed a language for method implementation within the modelling language
Advantage:
• We get completely rid of handcoding! Disadvantage:
• Large model: confusing?
• IDEs are less elaborated for such kind of programming Examples:
• MontiCore (DEX) provides possibilities to add methods and method bodies, e.g. in Java and python-style
• UML has its own action language defined
Prof. Dr. B. Rumpe
Lehrstuhl für Software Engineering RWTH Aachen
Page 42
Model Refers to Actions
The principle:
• Add references to the implementations in the model Variants:
• 1) GC calls the referenced HC: like delegation
• 2) Generator weaves the referenced artefact into the GC
Disadvantage:
• Model gets polluted
• Model contains references to artefacts that should be developed after the model unnecessary
• IDEs are less elaborated for such kind of programming
• For 2: Checking of syntactical correctness is deferred to the compiler (and thus too late)