130 likes | 231 Vues
Domain Specific Languages (Part 2). Based on http://martinfowler.com/dslwip. Using the JMenu API. JMenuBar mb = new JMenuBar(); f.setJMenuBar(mb); JMenu file = new JMenu("File"); file.setMnemonic('F'); mb.add(file); JMenuItem open = new JMenuItem("Open");
E N D
Domain Specific Languages(Part 2) Based on http://martinfowler.com/dslwip
Using the JMenu API JMenuBar mb = new JMenuBar(); f.setJMenuBar(mb); JMenu file = new JMenu("File"); file.setMnemonic('F'); mb.add(file); JMenuItem open = new JMenuItem("Open"); open.setMnemonic('O'); open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK)); open.addActionListener(new OpenCommand()); file.add(open); JMenuItem save = new JMenuItem("Save"); save.setMnemonic('S'); save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK)); save.addActionListener(new SaveCommand()); file.add(save); JMenuItem saveAs = new JMenuItem("Save As"); saveAs.setMnemonic('A'); saveAs.addActionListener(new SaveAsCommand()); file.add(saveAs);
Using the JMenu API (Cont.) JMenu edit = new JMenu("Edit"); edit.setMnemonic('E'); mb.add(edit); JMenuItem cut = new JMenuItem("Cut"); cut.setMnemonic('T'); cut.addActionListener(new CutCommand()); edit.add(cut); JMenuItem copy = new JMenuItem("Copy"); copy.setMnemonic('C'); copy.addActionListener(new CopyCommand()); edit.add(copy); JMenuItem paste = new JMenuItem("Paste"); paste.setMnemonic('P'); paste.addActionListener(new PasteCommand()); edit.add(paste);
Difficulties with JMenu • Repetition of the "current" menu variable • Code structure does not reflect menu structure • Tiny details – easy to get them wrong • A new menu item is created by Copy/Paste • Programmer often misses one of the adjustments
MenuBuilder w/o JSON • Two classes • Node • MenuBuilder • (See next 3 slides)
private static class Node { private final Map<String, Object> props = new HashMap<String, Object>(); private final List<Node> children = new ArrayList<Node>(); public JMenuItem create() { if (children.size() > 0) { JMenu result = new JMenu((String) get(NAME)); setShortcut(result); for (Node n : children) result.add(n.create()); return result; } JMenuItem result = new JMenuItem((String) get(NAME)); setShortcut(result); ActionListener al = (ActionListener) get(ACTION); if (al != null) result.addActionListener(al); return result; } private void setShortcut(JMenuItem result) { Character c = (Character) get(SHORTCUT); if (c != null) result.setMnemonic(c); } public void put(String key, Object value) { props.put(key, value); } private Object get(String key) { return props.get(key); } }
public class MenuBuilder { private Node node = new Node(); private MenuBuilder parent; public MenuBuilder() { this(null, ""); } private MenuBuilder(MenuBuilder parent, String name) { this.parent = parent; node.put(NAME, name); if (parent != null) parent.add(node); } public MenuBuilder child(String name) { return new MenuBuilder(this, name); } private void add(Node child) { node.children.add(child); } public MenuBuilder shortcut(char c) { node.put(SHORTCUT, c); return this; } ... }
public class MenuBuilder { ... public MenuBuilder action(ActionListener al) { node.put(ACTION, al); return this; } public MenuBuilder up() { return parent; } public JMenuBar build() { JMenuBar result = new JMenuBar(); for (Node n : node.children) result.add(n.create()); return result; } }
DSL Example • Read input file • Populate a relational database • Record per line Based on: http://martinfowler.com/articles/languageWorkbench.html http://www.infoq.com/presentations/domain-specific-languages
Input: Text #123456789012345678901234567890123456789012345678901234567890 PRCHFOWLER 10101MS0120050313 PRCHHOHPE 10201DX0320050315 PRCHJOHN 10301MR3720050329 ORDR10301MR99
Output: SQL Queries INSERT INTO Purchases (item_id,customer_id,date,amount) VALUES (10101MS,FOWLER,20050313,01) INSERT INTO Purchases (item_id,customer_id,date,amount) VALUES (10201DX,HOHPE,20050315,03) INSERT INTO Purchases (item_id,customer_id,date,amount) VALUES (10301MR,JOHN,20050329,37) INSERT INTO Orders (item_id,amount) VALUES (10301MR,99)
Naïve Solution public void run(Scanner sc) { while(sc.hasNext()) { String line = sc.nextLine(); if(line.startsWith("#")) continue; String code = line.substring(0, 4); if(code.equals("PRCH")) { String customerId = line.substring(4, 19).trim(); String itemId = line.substring(19, 26).trim(); String amount = line.substring(26, 28).trim(); String date = line.substring(28, 36).trim(); purchase(customerId, itemId, amount, date); } else if(code.equals("ORDR")) { String itemId = line.substring(4, 11).trim(); String amount = line.substring(11, 13).trim(); order(itemId, amount); } } } public void purchase(String c, String i, String a, String d) { ... } public void order(String i, String a) { ... }
DSL-based Solution new Processor("PRCH", "Purchases") .field("item_id", 19, 26) .field("customer_id", 4, 19) .field("date", 28, 36) .field("amount", 26, 28) .addTo(processors); new Processor("ORDR", "Orders") .field("item_id", 4, 11) .field("amount", 11, 13) .addTo(processors);