Model-Driven Software Development - Context-Sensitive Transformation
-
Upload
eelco-visser -
Category
Documents
-
view
2.349 -
download
1
description
Transcript of Model-Driven Software Development - Context-Sensitive Transformation
Context-Sensitive Transformation
Course IN4308Master Computer Science
Delft University of Technology
Eelco Visserhttp://eelcovisser.org
Lecture 8
Syntax Definition
Parse Table Signature Pretty-Print Table
TransformParse Pretty-Print
entity User { name :: String pw :: Secret}def output(u : User) {
@Entityclass User { String _user; public User getUser() { return _user; }syntax definition is basis of language definition
Coming up
Lecture 8: Context-sensitive transformation
★ design 2
★ transformation with dynamic rewrite rules
Lecture 9: Static analysis & error checking
★ name resolution, reference resolution
★ type analysis
Lecture 10: Code generation
★ string templates, code generation by model transformation
★ concrete object syntax
Lecture 11: Code generation strategies
★ customization of generated code
Outline
Design 2
★ designing a domain-specific language
Context-sensitive transformation
★ global-to-local, local-to-global
Rewriting strategies
★ controlling the application of rules
Dynamic rewrite rules
★ context-sensitive transformation with rewrite rules
Design 2Build your own DSL
Design 2: Purpose
Design a domain-specific language
Domain analysis
★ find abstractions in an existing programming domain
Language design
★ define a notation and translational semantics
Language implementation
★ build IDE and code generator
Understand tradeoffs in language design
Design 2: Ingredients
Syntax definition
★ elegant and efficient notation for a domain
Model transformation
★ reduce rich surface syntax to core language
Static analysis
★ find errors during editing
Code generation
★ generate complete implementation from models
Design 2: Considerations
Type system
★ do you catch errors at compile-time (in the IDE)?
Customization
★ can application developers work around lack of coverage?
Native interface
★ how are models integrated with environment?
Modularity
★ can models be broken down into smaller components?
Incremental language processing
Design 2: Inductive (bottom-up) design
Finding abstractions
Identify coding patterns
★ are there standard patterns in programs in this domain
Identify commonality
★ code generation templates
Identify variability
★ language constructs
Design 2: Examples
Improve existing language
- Software building DSL generating ANT
- XML transformation DSL generating XSLT
Abstract from existing framework/library
- DSL for Vaadin (http://vaadin.com)
- Javascript widget DSL generating JQuery or Dojo
- Game DSL generating Ogre C++
AndroidDSL
- Generate Java for Android applications
- Android & Nexus One phones available for experiments
JavaSwulimport javax.swing.*;import java.awt.*; public class Test3 { public static void main(String[] ps) { JFrame frame = frame { title = "Welcome!" content = panel of border layout { center = label { text = "Hello World" } south = panel of grid layout { row = { button { text = "cancel" } button { text = "ok"} } } } }; frame.pack(); frame.setVisible(true); }}
import javax.swing.*;import java.awt.*; public class Test3{ public static void main(String[] ps) { JButton jButton_1; JButton jButton_0; JPanel jPanel_1; JLabel jLabel_0; JPanel jPanel_0; JFrame jFrame_0; jFrame_0 = new JFrame(); jFrame_0.setTitle("Welcome!"); jPanel_0 = new JPanel(); BorderLayout borderLayout_0 = new BorderLayout(); jPanel_0.setLayout(borderLayout_0); jFrame_0.setContentPane(jPanel_0); JFrame frame = jFrame_0; jLabel_0 = new JLabel(); jLabel_0.setText("Hello World"); jPanel_0.add(jLabel_0, BorderLayout.CENTER); jPanel_1 = new JPanel(); GridLayout gridLayout_0 = new GridLayout(1, 2); jButton_0 = new JButton(); jButton_0.setText("cancel"); jButton_1 = new JButton(); jButton_1.setText("ok"); jPanel_1.setLayout(gridLayout_0); jPanel_1.add(jButton_0); jPanel_1.add(jButton_1); jPanel_0.add(jPanel_1, BorderLayout.SOUTH); frame.pack(); frame.setVisible(true); }}
Vaadin
package com.vaadin.demo.simpleaddressbook;
import com.vaadin.Application;import com.vaadin.data.Property;import com.vaadin.data.Property.ValueChangeEvent;import com.vaadin.data.util.IndexedContainer;import com.vaadin.ui.Button;import com.vaadin.ui.Form;import com.vaadin.ui.HorizontalLayout;import com.vaadin.ui.SplitPanel;import com.vaadin.ui.Table;import com.vaadin.ui.TextField;import com.vaadin.ui.VerticalLayout;import com.vaadin.ui.Window;import com.vaadin.ui.Button.ClickEvent;
public class SimpleAddressBook extends Application {
private static String[] fields = { "First Name", "Last Name", "Company", "Mobile Phone", "Work Phone", "Home Phone", "Work Email",
"Home Email", "Street", "Zip", "City", "State", "Country" };
private static String[] visibleCols = new String[] { "Last Name", "First Name", "Company" };
private Table contactList = new Table(); private Form contactEditor = new Form(); private HorizontalLayout bottomLeftCorner = new HorizontalLayout(); private Button contactRemovalButton; private IndexedContainer addressBookData = createDummyData();
@Override
public void init() { initLayout();
initContactAddRemoveButtons();
initAddressList();
initFilteringControls();
}
private void initLayout() { SplitPanel splitPanel = new SplitPanel( SplitPanel.ORIENTATION_HORIZONTAL);
setMainWindow(new Window("Address Book", splitPanel)); VerticalLayout left = new VerticalLayout(); left.setSizeFull();
left.addComponent(contactList);
contactList.setSizeFull();
left.setExpandRatio(contactList, 1);
splitPanel.addComponent(left);
splitPanel.addComponent(contactEditor);
contactEditor.setSizeFull();
contactEditor.getLayout().setMargin(true); contactEditor.setImmediate(true); bottomLeftCorner.setWidth("100%");
left.addComponent(bottomLeftCorner);
}
private void initContactAddRemoveButtons() { // New item button
bottomLeftCorner.addComponent(new Button("+", new Button.ClickListener() { public void buttonClick(ClickEvent event) { Object id = contactList.addItem();
contactList.setValue(id);
}
}));
// Remove item button
contactRemovalButton = new Button("-", new Button.ClickListener() { public void buttonClick(ClickEvent event) { contactList.removeItem(contactList.getValue());
contactList.select(null); }
});
contactRemovalButton.setVisible(false); bottomLeftCorner.addComponent(contactRemovalButton);
}
private String[] initAddressList() { contactList.setContainerDataSource(addressBookData);
contactList.setVisibleColumns(visibleCols);
contactList.setSelectable(true); contactList.setImmediate(true); contactList.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { Object id = contactList.getValue();
contactEditor.setItemDataSource(id == null ? null : contactList .getItem(id));
contactRemovalButton.setVisible(id != null); }
});
return visibleCols; }
private void initFilteringControls() { for (final String pn : visibleCols) { final TextField sf = new TextField(); bottomLeftCorner.addComponent(sf);
sf.setWidth("100%");
sf.setInputPrompt(pn);
sf.setImmediate(true); bottomLeftCorner.setExpandRatio(sf, 1);
sf.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { addressBookData.removeContainerFilters(pn);
if (sf.toString().length() > 0 && !pn.equals(sf.toString())) { addressBookData.addContainerFilter(pn, sf.toString(),
true, false); }
getMainWindow().showNotification(
"" + addressBookData.size() + " matches found");
}
});
}
}
private static IndexedContainer createDummyData() {
String[] fnames = { "Peter", "Alice", "Joshua", "Mike", "Olivia",
"Nina", "Alex", "Rita", "Dan", "Umberto", "Henrik", "Rene",
"Lisa", "Marge" };
String[] lnames = { "Smith", "Gordon", "Simpson", "Brown", "Clavel",
"Simons", "Verne", "Scott", "Allison", "Gates", "Rowling",
"Barks", "Ross", "Schneider", "Tate" };
IndexedContainer ic = new IndexedContainer();
for (String p : fields) { ic.addContainerProperty(p, String.class, "");
}
for (int i = 0; i < 1000; i++) { Object id = ic.addItem();
ic.getContainerProperty(id, "First Name").setValue(
fnames[(int) (fnames.length * Math.random())]); ic.getContainerProperty(id, "Last Name").setValue(
lnames[(int) (lnames.length * Math.random())]); }
return ic; }
}
Design 2: Advice
Choosing a domain
- choose a domain that you know or are interested to learn
Agile software development
- identify iterations
- minimize risks
- create working version in first week and evolve
Proposal
- don’t get stuck on it
- choose a domain and go
Model Transformation
Compilation by Normalization
Types of Model Transformation
Reduction to sub-language
★ Normalization
★ Desugaring
★ Optimization
★ Aspect weaving
★ Instrumentation
★ Refactoring
Translation to another language
★ Conversion
★ Migration
★ Compilation
Term Rewriting
Term Rewriting
Term rewrite rules
★ transform term to term
★ pattern matching
★ variable binding
★ substitution
Rewriting strategy
★ algorithm for applying rewrite rules
Term Rewrite Rule
desugar : Property(x, t) -> Property(x, t, [])
label/name
left-hand side pattern
right-hand side patternvariable
Rewrite Strategy
desugar-all = innermost(desugar)
strategy definitiongeneric strategy
strategy instantiation
innermost(s) apply transformation s exhaustively to all sub-terms of subject term in bottom-up order
Constant Folding
y := a + (3 * 5 - 17);
Assign( Var("y"), BinOp(Var("a"), "+", IntLit("25")))
Assign( Var("y"), Plus( Var("a") , Minus(Times(IntLit("3"), IntLit("5")), IntLit("17")) ))
y := (a + 25);
desugar + eval
parse
pretty-print
Constant Folding Rules
strategies
eval-all = innermost(desugar + eval)
rules eval : BinOp(IntLit(x), "+", IntLit(y)) -> IntLit(<addS>(x, y)) eval : BinOp(IntLit(x), "-", IntLit(y)) -> IntLit(<subtS>(x, y)) eval : BinOp(IntLit(x), "*", IntLit(y)) -> IntLit(<mulS>(x, y)) eval : BinOp(IntLit(x), "/", IntLit(y)) -> IntLit(<divS>(x, y))
Conditional Rewrite Rules
eval : BinOp(IntLit(x), "+", IntLit(y)) -> IntLit(<addS>(x, y))
eval : BinOp(IntLit(x), "+", IntLit(y)) -> IntLit(z) where z := <addS>(x, y)condition
match apply transformation
bound in condition
Context-sensitiveTransformation
Template Inliningdefine page blog(b : Blog) { header{output(b.name)} list{ for(p : Post in b.posts) { listitem{ outputPost(p) } } }}define outputPost(pst : Post) { navigate post(pst) { output(pst.name) }}define list() { <ul> elements </ul> }define listitem() { <li> elements </li> }define header() { <h1> elements </h1> }
define page blog ( b : Blog ) { <h1> output(b.name) </h1> <ul> for ( p : Post in b.posts ) { <li> navigate post(p) { output(p.name) } </li> } </ul>}
Context-sensitive Transformation
Local-to-local
★ replace term by another term
Local-to-global
★ local term influence terms in other parts of model
Global-to-local
★ global information influences transformation of local terms
define page blog(b : Blog) { header{output(b.name)} list{ for(p : Post in b.posts) { listitem{ outputPost(p) } } }}define outputPost(pst : Post) { navigate post(pst) { output(pst.name) }}define list() { <ul> elements </ul> }define listitem() { <li> elements </li> }define header() { <h1> elements </h1> }
define page blog ( b : Blog ) { <h1> output(b.name) </h1> <ul> for ( p : Post in b.posts ) { <li> navigate post(p) { output(p.name) } </li> } </ul>}
Inlining is Global-to-Local
outputPost(p) -> navigate post(p) { output(p.name) }where define outputPost(pst : Post) { navigate post(pst) { output(pst.name) } }
Inlining as Rewrite Problem
(this is not a valid Stratego rewrite rule)
Rewrite Rules are Context-free
desugar : Property(x, t) -> Property(x, t, [])
Simplification: Parameterless Templates
define page blog(b : Blog) { ... footer()}define footer() { navigate url(http://webdsl.org) { “WebDSL” }}
define page blog ( b : Blog ) { ... container() { navigate url(http://webdsl.org) { “WebDSL” } }}
Rewrite in Context
Inline : [def@TemplateDef(f,[],elem1*) | def1*] -> [def | def2*] where def2* := <alltd((Call(f) -> Call("container", elem1*)))> def1*
bound in contextlocal traversal
container needed to replace single call with multiple elements
Intermezzo:Rewriting Strategies
transformation
is
partial* function from terms to terms
* transformation may fail to apply to a term
Defining Transformations: Rules & Strategies
Rewrite rules are basic transformations
★ transform term matching lhs to instantiation of rhs
★ evaluate condition (where clause)
Strategies combine rules into complex transformations
★ select rules to apply
★ select algorithm to apply rules
Strategy combinators
★ composition of custom transformations
Strategy Combinators
id★ Identity
fail★ failure
s1 ; s2★ sequential composition
s1 <+ s2★ choice
Variables
{x, y : s}★ term variable scope
?t★ match term pattern t
!t★ build term pattern t
t1 := t2★ match term t2 to term (pattern) t1
<s> t★ apply strategy s to term t
Rewrite Rules
l : t1 -> t2 where s★ named, scoped rewrite rule
★ all variables in t1, t2, s are in scope of the rule
(t1 -> t2 where s)★ unscoped rewrite rule
★ variables are in scope of enclosing scope
Rewrite in Context
Inline : [def@TemplateDef(f,[],elem1*) | def1*] -> [def | def2*] where def2* := <alltd((Call(f) -> Call("container", elem1*)))> def1*
bound in context
[ TemplateDef( "footer" , [] , [Navigate(PageRef("webdsl", []), [String("WebDSL")])] ), TemplateDef( "blog" , [Param("b", SimpleType("Blog"))] , [Call("footer")] )]
Inline : [def@TemplateDef(f,[],elem*) | def1*] -> [def | def2*] where def2* := <alltd((Call(f) -> Call("container", elem*)))> def1*
f elem*
def1*Call(f)
Strategy Definitions
f(x,y|a,b) = s★ x, y are strategy parameters
★ a, b are term parameters
★ s uses all parameters
f(x) = s f = s★ term parameters are optional
★ all parameters are optional
Examples
★ try(s) = s <+ id★ repeat(s) = try(s; repeat(s))
Rules with Parameters
Transform all elements of a list
Invert order of elements of a list
Pair elements of two lists
inverse(|ys) : [] -> ys
inverse(|ys) : [x|xs] -> <inverse(|[x|ys])> xs
map(s) : [] -> []
map(s) : [x|xs] -> [<s>x | <map(s)> xs]
zip(s) : ([],[]) -> []
zip(s) : ([x|xs],[y|ys]) -> [<s>(x,y) | <zip(s)>(xs,ys)]
Traversal Combinators
all(s)★ apply s to all direct sub-terms (children)
one(s)★ apply s to exactly one sub-term
some(s)★ apply s to at least one sub-term
Traversal Strategies
topdown(s) = s; all(topdown(s))★ apply s to all sub-terms in top-down order
bottomup(s) = all(bottomup(s)); s★ apply s to all sub-terms in bottom-up order
oncetd(s) = s <+ one(oncetd(s))★ apply s to one sub-term
alltd(s) = s <+ all(alltd(s))★ apply s to frontier
Rewrite in Context: Local Traversal
Inline : [def@TemplateDef(f,[],elem1*) | def1*] -> [def | def2*] where def2* := <alltd((Call(f) -> Call("container", elem1*)))> def1*
local traversal
Dynamic Rewrite Rules
Rewrite in Context: Not Optimal
requires def before use local traversal for each declaration
Inline : [def@TemplateDef(f,[],elem1*) | def1*] -> [def | def2*] where def2* := <alltd((Call(f) -> Call("container", elem1*)))> def1*
Dynamic Rewrite Rules
separate traversal from rule definition (binding closures)
declare-inline : TemplateDef(f,[],elem1*) -> TemplateDef(f,[],elem1*) where rules( InlineTemplate : Call(f) -> Call("container", elem1*) )
inline = alltd(declare-inline); topdown(try(InlineTemplate))
Inline : [def@TemplateDef(f,[],elem1*) | def1*] -> [def | def2*] where def2* := <alltd((Call(f) -> Call("container", elem1*)))> def1*
outputPost(p) -> navigate post(p) { output(p.name) }where define outputPost(pst : Post) { navigate post(pst) { output(pst.name) } }
Inlining as Rewrite Problem (Revisited)
(informal)
declare-inline : TemplateDef(f,[],elem1*) -> TemplateDef(f,[],elem1*) where rules( InlineTemplate : Call(f) -> Call("container", elem1*) )
(formal; but not yet complete)
Template Parameterdefine page blog(b : Blog) { header{output(b.name)} list{ for(p : Post in b.posts) { listitem{ outputPost(p) } } }}define outputPost(pst : Post) { navigate post(pst) { output(pst.name) }}define list() { <ul> elements </ul> }define listitem() { <li> elements </li> }define header() { <h1> elements </h1> }
define page blog ( b : Blog ) { <h1> output(b.name) </h1> <ul> for ( p : Post in b.posts ) { <li> navigate post(p) { output(p.name) } </li> } </ul>}
declare-inline : def@TemplateDef(mod*,f,param*,elem1*) -> def where rules( InlineTemplate : Call(f, e*, []) -> Call("container", [], elem3*) where elem3* := <substitute> (param*, e*, elem1*) ) substitute : (param*, e*, elem1*) -> elem2* where {| Subst : <zip(bind-arg)> (param*, e*) ; elem2* := <alltd(Subst)> elem1* |} bind-arg : (Param(x, t), e) -> (Param(x, t), e) where rules( Subst : Var(x) -> e )
Inlining Templates with Parameters
declare-inline : def@TemplateDef(mod*,f,param*,elem1*) -> def where rules( InlineTemplate : Call(f, e*, elem2*) -> Call("container", [], elem3*) where {| Subst : rules( Subst : Elements() -> Call("container",[],elem2*) ) ; elem3* := <substitute> (param*, e*, elem1*) |} )
define list() { <ul> elements </ul> }
Element Parameters
Removing Intermediate Structures
rules // remove containers desugar-container : [Call("container",[], elem1*) | elem2*] -> [elem1*, elem2*] desugar : elem1* -> elem2* where elem2* := <at-suffix(desugar-container)> elem1*
container needed to replace single call with multiple elements
Inlining Strategy
module template-inlining
imports libstratego-libimports include/nwlimports desugar
strategies inline-all = desugar-all; alltd(declare-inline); innermost(desugar <+ InlineTemplate)
rules declare-inline : ...
module template-inlining
imports libstratego-libimports include/nwlimports desugar
strategies inline-all = desugar-all; alltd(declare-inline); innermost(desugar <+ InlineTemplate)
rules declare-inline : TemplateDef(mod*,f,param*,elem1*) -> TemplateDef(mod*,f,param*,elem1*) where rules( InlineTemplate : Call(f, e*, elem2*) -> Call("container", [], elem3*) where {| Subst : rules( Subst : Elements() -> Call("container", [], elem2*) ) ; elem3* := <substitute> (param*, e*, elem1*) |} ) substitute : (param*, e*, elem1*) -> elem2* where {| Subst : <zip(bind-arg)> (param*, e*) ; elem2* := <alltd(Subst)> elem1* |} bind-arg : (Param(x, t), e) -> (Param(x, t), e) where rules( Subst : Var(x) -> e )
rules // remove containers desugar-container : [Call("container",[], elem1*) | elem2*] -> [elem1*, elem2*] desugar : elem1* -> elem2* where elem2* := <at-suffix(desugar-container)> elem1*
Template Inlining Transformation
Free Variable Capture
Free Variable Capture in Template Inlining
define page blogfront(b : Blog) { header{output(b.name)} list{ for(p : Post in b.posts) { listitem{ postInline(p) { par{ "Posted by " outputUser(p.author) } } } } }}define postInline(pst : Post) { header{output(pst.title)} output(pst.text) for(p : Tag in pst.tags) { elements }}
define page blogfront(b : Blog) { header{output(b.name)} list{ for(p : Post in b.posts) { listitem{ postInline(p) { par{ "Posted by " outputUser(p.author) } } } } }}define postInline(pst : Post) { header{output(pst.title)} output(pst.text) for(p : Tag in pst.tags) { elements }}
define page blogfront(b : Blog) { <h1> output(b.name) </h1> <ul> for(p : Post in b.posts) { <li> <h1>output(p.title)</h1> output(p.text) for ( p : Tag in p.tags ) { <p> "Posted by " navigate user(p.author) { output(p.author.name) } </p> } </li> } </ul>}
Free Variable Capture in Template Inlining
define page blogfront(b : Blog) { for(p : Post in b.posts) { for(p : Tag in p.tags) { output(p.name) "Posted by " navigate user(p.author) { output(p.author.name) } } }}
Free Variable Capture in Template Inlining
define page blogfront(b : Blog) { for(p : Post in b.posts) { postInline(p) { "Posted by " outputUser(p.author) } }}define postInline(pst : Post) { for(p : Tag in pst.tags) { output(p.name) elements }}
Avoiding Free Variable Capture
substitute-args : (param*, e*, elem1*) -> elem2* where {| Subst : <zip(bind-arg)> (param*, e*) ; elem2* := <substitute> elem1* |} substitute = alltd(Subst <+ rename-bound) rename-bound : ForElem(x, t, e1, elem1*) -> ForElem(y, t, e2, elem2*) where {| Subst : y := <newname> x ; e2 := <substitute> e1 ; rules( Subst : Var(x) -> Var(y) ) ; elem2* := <substitute> elem1* |}
rename bound variables
define page blogfront(b : Blog) { for(p : Post in b.posts) { for(p3 : Tag in p.tags) { output(p3.name) "Posted by " navigate user(p.author) { output(p.author.name) } } }}
Free Variable Capture in Template Inlining
define page blogfront(b : Blog) { for(p : Post in b.posts) { postInline(p) { "Posted by " outputUser(p.author) } }}define postInline(pst : Post) { for(p : Tag in pst.tags) { output(p.name) elements }}
Aspect Weaving
Aspect Weaving
Aspect definition
★ modular definition of cross cutting concerns
Aspect weaving
★ apply aspects to base program
Applications
★ instrumentation for logging, tracing, debugging, profiling
★ access control, data validation, entity extension
Access Control Rulesdefine page post(p : Post) { header{output(p.title)} output(p.text) par{ "Posted by " outputUser(p.author) } navigate editpost(p) { "Edit" }}
rule page editpost(pst : Post) { principal == pst.blog.author}
define page editpost(p : Post) { action save() { return post(p); } header{output(p.title)} form{ input(p.url) input(p.title) input(p.text) submit save() { "Save" } }}
Access Control Weavingdefine page post(p : Post) { header{output(p.title)} output(p.text) par{ "Posted by " outputUser(p.author) } navigate editpost(p) { "Edit" }}
rule page editpost(pst : Post) { principal == pst.blog.author}
define page editpost(p : Post) { action save() { return post(p); } header{output(p.title)} form{ input(p.url) input(p.title) input(p.text) submit save() { "Save" } }}
Access Control Weaving: Protect Pagedefine page post(p : Post) { header{output(p.title)} output(p.text) par{ "Posted by " outputUser(p.author) } navigate editpost(p) { "Edit" }}
rule page editpost(pst : Post) { principal == pst.blog.author}
define page editpost(p : Post) { action save() { return post(p); } header{output(p.title)} form{ input(p.url) input(p.title) input(p.text) submit save() { "Save" } }}
define page editpost(p : Post) { init { if(!(principal == pst.blog.author)) { return accessdenied() ; } } action save() { return post(p) ; } header{output(p.title)} form{ input(p.url) input(p.title) input(p.text) submit save ( ) { "Save" } }}
Access Control Weaving: Protect Linkdefine page post(p : Post) { header{output(p.title)} output(p.text) par{ "Posted by " outputUser(p.author) } navigate editpost(p) { "Edit" }}
rule page editpost(pst : Post) { principal == pst.blog.author}
define page editpost(p : Post) { action save() { return post(p); } header{output(p.title)} form{ input(p.url) input(p.title) input(p.text) submit save() { "Save" } }}
define page editpost(p : Post) { init { if(!(principal == pst.blog.author)) { return accessdenied() ; } } action save() { return post(p) ; } header{output(p.title)} form{ input(p.url) input(p.title) input(p.text) submit save ( ) { "Save" } }}
define page post ( p : Post ) { header{output(p.title)} output(p.text) par{"Posted by "outputUser(p.author)} if(principal == p.blog.author) { navigate editpost(p) { "Edit" } } }
Access Control Weaving: Strategy
weave-ac-rules = alltd(declare-ac-rule); bottomup(try(ProtectPage <+ ProtectNavigate))
Access Control Weaving: Protect Navigate
declare-ac-rule : r@Rule([Page()], f, param1*, e) -> r where rules( ProtectNavigate : elem@Navigate(PageRef(f, e*), elem*) -> If(e2,Block([elem]),Block([])) where e2 := <substitute-args> (param1*, e*, e) )
Access Control Weaving: Protect Page
declare-ac-rule : r@Rule([Page()], f, param1*, e) -> r where rules( ProtectNavigate : ...
ProtectPage : TemplateDef([Page()], f, param2*, elem*) -> TemplateDef([Page()], f, param2*, [Init([ If(Not(e), Block([ReturnPage(PageRef("accessdenied", []))]), Block([]))]), elem*]) where e2 := <substitute-args> (param1*, <map(param-to-exp)> param2*, e) )
param-to-exp : Param(x, t) -> Var(x)
Access Control Weaving: Complete*
weave-ac-rules = alltd(declare-ac-rule); bottomup(try(ProtectPage <+ ProtectNavigate))declare-ac-rule : r@Rule([Page()], f, param1*, e) -> r where rules( ProtectPage : TemplateDef([Page()], f, param2*, elem1*) -> TemplateDef([Page()], f, param2*, [Init([ If(Not(e), Block([ReturnPage(PageRef("accessdenied", []))]), Block([]))]), elem1*]) where e2 := <substitute-args> (param1*, <map(param-to-exp)> param2*, e) ProtectNavigate : elem@Navigate(PageRef(f, e*), elem*) -> If(e2,Block([elem]),Block([])) where e2 := <substitute-args> (param1*, e*, e) )param-to-exp : Param(x, t) -> Var(x)
* complete specification for this limited example; WebDSL AC is more complex
Extend Entity
module blog
entity Post { url : String (id) title : String (name) text : WikiText blog : Blog (inverse:posts) author : User blog : Blog}
modular extensibility => more cohesion (?)
module tags
entity Tag { key : String (id) title : String (name) text : WikiText posts : Set<Post> }
extend entity Post { tags : Set<Tag> (inverse:posts)}
Extend Entity
module blog
entity Post { url : String (id) title : String (name) text : WikiText blog : Blog (inverse:posts) author : User blog : Blog}
modular extensibility => more cohesion (?)
module tags
entity Tag { key : String (id) title : String (name) text : WikiText posts : Set<Post> }
extend entity Post { tags : Set<Tag> (inverse:posts)}
module woven
entity Post { url : String (id) title : String (name) text : WikiText blog : Blog (inverse:posts) author : User blog : Blog tags : Set<Tag> (inverse:posts)}
entity Tag { key : String (id) title : String (name) text : WikiText posts : Set<Post> }
Other Model Transformations
Other Applications of Model Transformation
Refactoring
★ behaviour preserving transformation to improve design
★ e.g. extract/inline function/template/entity
Difference detection
★ detect differences between two models
Migration
★ update model to conform to new meta-model
Optimization
★ derive more efficient version
★ e.g. query prefetching
Schedule
Case 3
★ Syntax definition & term rewriting
★ Deadline:
Design 2
★ Make a proposal (can be submitted separately)
★ Deadline:
Lab this week
★ Install Spoofax
★ Make Case 3
Next
★ Lecture 9: static analysis