User-Interface
   Programmierung mit
      externen DSLs
       Sven Efftinge, Jan Köhnlein (itemis AG)




              ...
Zielarchitektur



• Oracle DB
• Java Rich Client
• JPA
• Spring
• Swing / JGoodies Forms   3




Mengengerüst
 • 1722 Tab...
Domänenmodel
                                                                                          5




@SuppressWarn...
@SuppressWarnings(quot;serialquot;)
@Entity
 Entity
@Table(name = quot;BUCHUNGSKREISE_Fquot;)
               BUCHUNGSKREIS...
entity BuchungskreiseF
              (id=bkrId sequenceName=BKR_SEQ) {
            }




                              TAB...
Formulare

            10




            11
public class PersonenForm extends
Form<Personen> {




                                                         11




   ...
public class PersonenForm extends
        Form<Personen> {




                                                           ...
public class PersonenForm extends
        Form<Personen> {




                                                           ...
Graphische GUI-DSL




                     13




Graphische GUI-DSL




                     13
ID          NAME    PROP1    DATE    ATTR1
ID        NAME   PROP1        DATE   ATTR1




                                ...
16




addValidator(new Validator<Institutionen>() {
! ! ! @Override
! ! ! public ValidationResult validate(final Institut...
Framework-Code




addValidator(new Validator<Institutionen>() {
! ! ! @Override
! ! ! public ValidationResult validate(fi...
Framework-Code
Nullpointer abfragen
Static imports

addValidator(new Validator<Institutionen>() {
! ! ! @Override
! ! ! pu...
Internal DSL mit Java
 !   void checkEsrMsg() {
 !   ! if (!checkPcKontoNrPruefziffer(parseLong(_this.getEsrNr())))
 !   !...
Anzahl Zeichen im Vergleich (nur Entity-DSL)
                                         29248 (DSL)
  Mit DSL               ...
Fragen?



          22
Upcoming SlideShare
Loading in …5
×

Domain-Specific Languages in der Praxis

961 views

Published on

Zeigt den Einsatz von externen und internen DSLs in einem kommerziellen Projekt.

Published in: Technology, Business
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
961
On SlideShare
0
From Embeds
0
Number of Embeds
10
Actions
Shares
0
Downloads
24
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Domain-Specific Languages in der Praxis

  1. 1. User-Interface Programmierung mit externen DSLs Sven Efftinge, Jan Köhnlein (itemis AG) 1 Ausgangslage • DB-Anwendung • Oracle DB • OracleForms 2
  2. 2. Zielarchitektur • Oracle DB • Java Rich Client • JPA • Spring • Swing / JGoodies Forms 3 Mengengerüst • 1722 Tabellen • 19572 Spalten • über 300 Forms Aufgabe • Abstraktionen finden • Code vereinfachen 4
  3. 3. Domänenmodel 5 @SuppressWarnings(quot;serialquot;) @Entity Entity @Table(name = quot;BUCHUNGSKREISE_Fquot;) BUCHUNGSKREISE_F public class BuchungskreiseF extends AbstractEntity implements Serializable { ! ! @SuppressWarnings(quot;unusedquot;) ! @Id Id ! @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = quot;bkrIdSeqquot;) ! @SequenceGenerator(name = quot;bkrIdSeqquot;, sequenceName = quot;BKR_SEQquot;, allocationSize = 1) BKR_SEQ ! @Column(name = quot;BKR_IDquot;, nullable = false BKR_ID false) ! private Long bkrId bkrId; ! public Long getBkrId() { ! ! return bkrId; ! } ! public void setBkrId(final Long bkrId) { ! ! this.bkrId = bkrId; ! } ! @Column(name = quot;KONTO_NRquot;, nullable = false length = 45 KONTO_NR false, 45) ! private String kontoNr; kontoNr ! public String getKontoNr() { ! ! return kontoNr; ! } ! public void setKontoNr(final String kontoNr) { ! ! String oldValue = this.kontoNr; ! ! this.kontoNr = kontoNr; ! ! firePropertyChangeEvent(quot;kontoNrquot;, oldValue, this.kontoNr); ! } 6 ! @Column(name = quot;RG_NR_BKR_IDENTIFIKATORquot;, nullable = false, length = 1) ! private Long rgNrBkrIdentifikator; ! public Long getRgNrBkrIdentifikator() {
  4. 4. @SuppressWarnings(quot;serialquot;) @Entity Entity @Table(name = quot;BUCHUNGSKREISE_Fquot;) BUCHUNGSKREISE_F public class BuchungskreiseF extends AbstractEntity implements Serializable { ! ! @SuppressWarnings(quot;unusedquot;) ! @Id Id ! @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = quot;bkrIdSeqquot;) ! @SequenceGenerator(name = quot;bkrIdSeqquot;, sequenceName = quot;BKR_SEQquot;, allocationSize = 1) BKR_SEQ ! @Column(name = quot;BKR_IDquot;, nullable = false BKR_ID false) ! private Long bkrId bkrId; ! public Long getBkrId() { ! ! return bkrId; ! } ! public void setBkrId(final Long bkrId) { ! ! this.bkrId = bkrId; ! } ! @Column(name = quot;KONTO_NRquot;, nullable = false length = 45 KONTO_NR false, 45) ! private String kontoNr; kontoNr ! public String getKontoNr() { ! ! return kontoNr; ! } ! public void setKontoNr(final String kontoNr) { ! ! String oldValue = this.kontoNr; ! ! this.kontoNr = kontoNr; ! ! firePropertyChangeEvent(quot;kontoNrquot;, oldValue, this.kontoNr); ! } 6 ! @Column(name = quot;RG_NR_BKR_IDENTIFIKATORquot;, nullable = false, length = 1) ! private Long rgNrBkrIdentifikator; ! public Long getRgNrBkrIdentifikator() { ! ! return rgNrBkrIdentifikator; ! } ! public void setRgNrBkrIdentifikator(final Long rgNrBkrIdentifikator) { ! ! Long oldValue = this.rgNrBkrIdentifikator; External DSL mit TMF Xtext ! ! this.rgNrBkrIdentifikator = rgNrBkrIdentifikator; ! ! firePropertyChangeEvent(quot;rgNrBkrIdentifikatorquot;, oldValue, ! ! ! ! this.rgNrBkrIdentifikator); ! } @Column(name = quot;REFERENZCODE_KONTO_NRquot;,BUCHUNGSKREISE_F ! nullable = false, length = 45) ! private String referenzcodeKontoNr; entity BuchungskreiseF ! public String getReferenzcodeKontoNr() { ! (id=bkrId sequenceName=BKR_SEQ) { ! return referenzcodeKontoNr; ! } String kontoNr ! public void setReferenzcodeKontoNr(final String referenzcodeKontoNr) { ! ! String oldValue = this.referenzcodeKontoNr; RG_NR_BKR_IDENTIFIKATOR ! ! this.referenzcodeKontoNr = referenzcodeKontoNr; ! ! firePropertyChangeEvent(quot;referenzcodeKontoNrquot;, oldValue, Long rgNrBkrIdentifikator ! ! ! ! this.referenzcodeKontoNr); ! } String referenzcodeKontoNr ! @Column(name = quot;PC_NR_RGquot;, nullable = false, length = 45) ! private String pcNrRg; ! public String getPcNrRg() { } ! ! return pcNrRg; ! } ! public void setPcNrRg(final String pcNrRg) { ! ! String oldValue = this.pcNrRg; ! ! this.pcNrRg = pcNrRg; 7 ! ! firePropertyChangeEvent(quot;pcNrRgquot;, oldValue, this.pcNrRg); ! } ! @Column(name = quot;PC_NR_PVAquot;, nullable = false, length = 45) ! private String pcNrPva;
  5. 5. entity BuchungskreiseF (id=bkrId sequenceName=BKR_SEQ) { } TABLE BUCHUNGSKREISE_F ID NAME PROP1 DATE ATTR1 ID NAME PROP1 DATE ATTR1 ID NAME PROP1 DATE ATTR1 ID NAME PROP1 DATE ATTR1 ID NAME PROP1 DATE ATTR1 ID NAME PROP1 DATE ATTR1 ID NAME PROP1 DATE ATTR1 ID NAME PROP1 DATE ATTR1 Database Schema 8 9
  6. 6. Formulare 10 11
  7. 7. public class PersonenForm extends Form<Personen> { 11 public class PersonenForm extends Form<Personen> { public class PersonenHauptSubForm extends SubForm<Personen> { 11
  8. 8. public class PersonenForm extends Form<Personen> { public class PersonenHauptSubForm extends SubForm<Personen> { private JComponent vornameTextField; 11 public class PersonenForm extends Form<Personen> { public class PersonenHauptSubForm extends SubForm<Personen> { @Override protected void initComponents() { ... vornameTextField = builder.createTextField(desc.vorname(), private JComponent vornameTextField; Editable.PROPERTY_DEFAULT, MANDATORY); ! ! gepardBuilder.setNoLeadingBlanks (vornameTextField); 11
  9. 9. public class PersonenForm extends Form<Personen> { public class PersonenHauptSubForm extends SubForm<Personen> { @Override ! protected JComponent buildPanel() { TwoColumnsPanelBuilder builder = @Override protected void initComponents() { ... TwoColumnsPanelBuilder.instance(getBuilderFactory(), vornameTextField = private JComponent builder.createTextField(desc.vorname(), vornameTextField; Editable.PROPERTY_DEFAULT, MANDATORY); ! ! gepardBuilder.setNoLeadingBlanks getResourceMap()); (vornameTextField); ... builder.add(quot;vornamequot;, vornameTextField); ! 11 GUI-Builder • WYSIWYG • teilweise mit Databinding • zu viele Freiheitsgrade • Referenz auf Java-Code, nicht auf Domain-DSL 12
  10. 10. Graphische GUI-DSL 13 Graphische GUI-DSL 13
  11. 11. ID NAME PROP1 DATE ATTR1 ID NAME PROP1 DATE ATTR1 Referenzen ID NAME PROP1 DATE ATTR1 ID NAME PROP1 DATE ATTR1 ID NAME PROP1 DATE ATTR1 ID NAME PROP1 DATE ATTR1 ID NAME PROP1 DATE ATTR1 ID NAME PROP1 DATE ATTR1 model : gepard; import quot;platform:/resource/com.affichage.it21.gp.dao/src/main/model/types.daoquot; com.affichage.it21.gp.dao { ! flaechen { ! ! readOnly entity WaehrungF (id =(rvLowValue)) { ! ! } ! ! readOnly entity GepardVerwendungPvF (id =(pvOid)) { ! ! ! temporal manyToOne GeschpartnerAllBsF geschpartner (joinColum ! ! } ! } ! ! verkauf { ! ! readOnly entity GepardVerwendungKdvtF (id =(kdvtId)) { ! ! ! temporal notNull manyToOne GeschpartnerAllBsF geschpartner (j ! ! ! notNull Number istLangfrist (castTo=Boolean) ! ! ! notNull Number istLokaldispo (castTo=Boolean) ! ! } ! } ! gepard { ! ! readOnly entity AbcKundenF (id = (rvLowValue)) { ! ! 14 Validierung 15
  12. 12. 16 addValidator(new Validator<Institutionen>() { ! ! ! @Override ! ! ! public ValidationResult validate(final Institutionen institution) { ! ! ! ! final ValidationResult result = new ValidationResult(); ! ! ! ! if (institution != null && institution.getEsrNr() != null !!!!! && !CheckUtils.checkPcKontoNrPruefziffer( Long.parseLong(institution.getEsrNr())) { ! ! ! ! ! result.add(new SimpleValidationMessage( getResourceMap().getString(quot;validation.esr.msgquot;), Severity.ERROR, getModel(Institutionen.DESC.esrNr()))); !!!!} ! ! ! ! return result; !!!} ! ! }); 17
  13. 13. Framework-Code addValidator(new Validator<Institutionen>() { ! ! ! @Override ! ! ! public ValidationResult validate(final Institutionen institution) { ! ! ! ! final ValidationResult result = new ValidationResult(); ! ! ! ! if (institution != null && institution.getEsrNr() != null !!!!! && !CheckUtils.checkPcKontoNrPruefziffer( Long.parseLong(institution.getEsrNr())) { ! ! ! ! ! result.add(new SimpleValidationMessage( getResourceMap().getString(quot;validation.esr.msgquot;), Severity.ERROR, getModel(Institutionen.DESC.esrNr()))); !!!!} ! ! ! ! return result; !!!} ! ! }); 17 Framework-Code Nullpointer abfragen addValidator(new Validator<Institutionen>() { ! ! ! @Override ! ! ! public ValidationResult validate(final Institutionen institution) { ! ! ! ! final ValidationResult result = new ValidationResult(); ! ! ! ! if (institution != null && institution.getEsrNr() != null !!!!! && !CheckUtils.checkPcKontoNrPruefziffer( Long.parseLong(institution.getEsrNr())) { ! ! ! ! ! result.add(new SimpleValidationMessage( getResourceMap().getString(quot;validation.esr.msgquot;), Severity.ERROR, getModel(Institutionen.DESC.esrNr()))); !!!!} ! ! ! ! return result; !!!} ! ! }); 17
  14. 14. Framework-Code Nullpointer abfragen Static imports addValidator(new Validator<Institutionen>() { ! ! ! @Override ! ! ! public ValidationResult validate(final Institutionen institution) { ! ! ! ! final ValidationResult result = new ValidationResult(); ! ! ! ! if (institution != null && institution.getEsrNr() != null !!!!! && !CheckUtils.checkPcKontoNrPruefziffer( Long.parseLong(institution.getEsrNr())) { ! ! ! ! ! result.add(new SimpleValidationMessage( getResourceMap().getString(quot;validation.esr.msgquot;), Severity.ERROR, getModel(Institutionen.DESC.esrNr()))); !!!!} ! ! ! ! return result; !!!} ! ! }); 17 Framework-Code Nullpointer abfragen Static imports Bibliotheks Methoden definieren und benutzen addValidator(new Validator<Institutionen>() { ! ! ! @Override ! ! ! public ValidationResult validate(final Institutionen institution) { ! ! ! ! final ValidationResult result = new ValidationResult(); ! ! ! ! if (institution != null && institution.getEsrNr() != null !!!!! && !CheckUtils.checkPcKontoNrPruefziffer( Long.parseLong(institution.getEsrNr())) { ! ! ! ! ! result.add(new SimpleValidationMessage( error(quot;validation.esr.msgquot;, desc.esrNr()); getResourceMap().getString(quot;validation.esr.msgquot;), Severity.ERROR, getModel(Institutionen.DESC.esrNr()))); !!!!} ! ! ! ! return result; !!!} ! ! }); 17
  15. 15. Internal DSL mit Java ! void checkEsrMsg() { ! ! if (!checkPcKontoNrPruefziffer(parseLong(_this.getEsrNr()))) ! ! ! error(quot;validation.esr.msgquot;,desc.esrNr()); ! } • Junit-like • fängt Nullpointer-Exceptions 18 Warum Abstrahieren? 19
  16. 16. Anzahl Zeichen im Vergleich (nur Entity-DSL) 29248 (DSL) Mit DSL + 49948 (Codegenerator) + 170 * Anzahl Entitäten Ohne DSL 7303 * Anzahl Entitäten 300 TZ 240 TZ 11 Entitäten 180 TZ 120 TZ 60 TZ 0 TZ 0 20 40 20 Software Life-Cycle Costs (Schach 2002) 2% 5% 6% Requirements 5% Specification Design 7% Coding 8% Unit Testing Integration 67% Maintenance 21
  17. 17. Fragen? 22

×