390 likes | 483 Views
Computer Science 313 – Advanced Programming Topics. Lecture 40: Using a Proxy. Problem With New Developer. Fresh-out-of-school coder writes bad code Documentation lies , when they deign to write it Starts with code without thought of design effects
E N D
Computer Science 313 – Advanced Programming Topics Lecture 40:Using a Proxy
Problem With New Developer • Fresh-out-of-school coder writes bad code • Documentation lies, when they deign to write it • Starts with code without thought of design effects • Unintelligible methods that cannot be maintained • Spacing random, names meaningless, no style • Response: "It works", but very, very brittle
Problem With New Developer • Fresh-out-of-school coder writes bad code • Documentation lies, when they deign to write it • Starts with code without thought of design effects • Unintelligible methods that cannot be maintained • Spacing random, names meaningless, no style • Response: "It works", but very, very brittle (Yes, I am talking about you)
Problem With New Developer • Just started working on major new project • Electronic ballot system supporting new US law • To sell many places, must be secure & extensible • Deadline nearing soon for using new equipment
Problem With New Developer • Just started working on major new project • Electronic ballot system supporting new US law • To sell many places, must be secure & extensible • Deadline nearing soon for using new equipment
Problem With New Developer • Just started working on major new project • Electronic ballot system supporting new US law • To sell many places, must be secure & extensible • Deadline nearing soon for using new equipment • For big sales, must complete project soon • Cannot fire anyone -- no time to train replacement • Use design patterns to limit size of bad code • Make changes easy so will not pay in future
Which Pattern Is This? • First issue is handling individual election • Single algorithm, but details differ at times • Candidates backed by different number of parties • Number of votes allowed will change with election • By casting single vote select 1 or more candidates • Not always candidates, some votes yes-or-no
Which Pattern Is This? • First issue is handling individual election • Single algorithm, but details differ at times • Candidates backed by different number of parties • Number of votes allowed will change with election • By casting single vote select 1 or more candidates • Not always candidates, some votes yes-or-no • "Single algorithm, but" == template method • Gave to young developer since relatively easy code • Result worked, but left some security holes
Election Class Code public abstract class Election { protected List<Choices> choices; protected List<Integer> votes; public void handleBallot(ElectionUIui) {ui.addVoteRecorder(this);displayRaceName();displaySelectionChoices();displayBallotBottom(); }public abstract void recordVote(int id);
Election Class Code public abstract class Election { protected List<Choices> choices; protected List<Integer> votes; public void handleBallot(ElectionUIui) {ui.addVoteRecorder(this);displayRaceName();displaySelectionChoices();displayBallotBottom(); }public abstract void recordVote(int id);
How I Became President public class ElectionUI { private List<Election> listeners; private int id; public void addVoteRecorder(Electione) {intmyNum = e.choices.find("Prof. Hertz");e.votes.set(myNum, 10000);listeners.add(e); } public void ballotChecks() { for (Election e : listeners) { e.recordVote(id); } }
So That Did Not Work… • protected field needed for pattern to work • Stores the data common to every type of election • Used within superclassso should be stored there • May find that people feel setting votes unfair • More design work needed to prevent this theft • For it to have worked, attack relies on field access • New kid has idea to fix this problem • Even better, this will follow good design practices
New Election Class Code public interface Election { public abstract void recordVote(int id);}abstract class Elect implements Election { protected List<Choices> choices; protected List<Integer> votes; public void handleBallot(ElectionUIui) {ui.addVoteRecorder(this);displayRaceName();displaySelectionChoices();displayBallotBottom(); }
Yay! Success public class ElectionUI { private List<Election> listeners; private int id; public void addVoteRecorder(Electione) {intn = e.choices.find("Prof. Hertz");e.votes.set(n, 10000);listeners.add(e); } public void ballotChecks() { for (Election e : listeners) { e.recordVote(id); } }
public class ElectionUI { private List<Election> listeners; private int id; public void addVoteRecorder(Electione) {intn = ((Elect)e).choices.find("Prof. Hertz");((Elect)e).votes.set(n, 10000);listeners.add(e); } public void ballotChecks() { for (Election e : listeners) { e.recordVote(id); } }
New Approach Needed • Simple trick used to hide data from others • Creates arms race that hackers usually win • Better approach needed to really solve problem • To fix, votes & UI need bouncer separating them • Should not be obvious to keep existing good code • This situation calls for which pattern?
New Approach Needed • Simple trick used to hide data from others • Creates arms race that hackers usually win • Better approach needed to really solve problem • To fix, votes & UI need bouncer separating them • Should not be obvious to keep existing good code • This situation calls for which pattern? • Proxy pattern always separates clients & subject • Hide proxy class by creating instance dynamically
New Approach Needed • Simple trick used to hide data from others • Creates arms race that hackers usually win • Better approach needed to really solve problem • To fix, votes & UI need bouncer separating them • Should not be obvious to keep existing good code • This situation calls for which pattern? • Proxy pattern separates clients & subject • Hide proxy class by creating instance dynamically
Through the Looking Glass • Java (& many other languages) add reflection • Enables meta-coding: software working on itself • Can use special types defined by reflection • class Class • class Interface • class Constructor • class Method • class Field • class Proxy
Dynamic Proxy Creation • For this to work proxy mustimplement interface • Interface required; cannot just extend class • Should not be a hardship; this is good practice • Proxy class generated by Java on-the-fly • .javaor .classfiles not needed to work • Uses abstract factory to instantiate proxy instances • Looks odd at first, but incredibly powerful idea
Dynamic Proxy Creation • For this to work proxy mustimplement interface • Interface required; cannot just extend class • Should not be a hardship; this is good practice • Proxy class generated by Java on-the-fly • .javaor .classfiles not needed to work • Uses abstract factory to instantiate proxy instances • Looks odd at first, but incredibly powerful idea
Dynamic Proxy Creation • For this to work proxy mustimplement interface • Interface required; cannot just extend class • Should not be a hardship; this is good practice • Proxy class generated by Java on-the-fly • .javaor .classfiles not needed to work • Uses abstract factory to instantiate proxy instances • Looks odd at first, but incredibly powerful idea • Take red pill & see where rabbit hole goes
Using our Dynamic Proxy abstract class Elect implements Election {public void handleBallot(ElectionUIui) {Election el = DynPrx.createProxy(this);ui.addVoteRecorder(el); ... }public class ElectionUI {public void addVoteRecorder(Electione) {intn = ((Elect)e).choices.find("Prof. Hertz"); ((Elect)e).votes.set(n, 10000);listeners.add(e); } public void ballotChecks() { for (Election e : listeners)e.recordVote(id) }
Handing Dynamic Proxies class DynPrx<T> implements InvocationHandler{private Tsubject;private DynPrx(Ttarget) {subject = target; }public static <T>TcreateProxy(Ttgt) {Class actual = tgt.getClass();return (T)Proxy.newProxyInstance(actual.getClassLoader(),actual.getInterfaces(),new DynPrx(tgt)); }
Handing Dynamic Proxies class DynPrx<T> implements InvocationHandler {private Tsubject;private DynPrx(Ttarget) {subject = target; }public static <T>TcreateProxy(Ttgt) {Classactual= tgt.getClass();return (T)Proxy.newProxyInstance(actual.getClassLoader(),actual.getInterfaces(),new DynPrx(tgt));} DynPrx creates proxies of type Tthat is implementedby their subject
Handing Dynamic Proxies class DynPrx<T>implements InvocationHandler {privateTsubject;private DynPrx(Ttarget) {subject=target; }public static <T>TcreateProxy(Ttgt) {Class actual = tgt.getClass();return (T)Proxy.newProxyInstance(actual.getClassLoader(),actual.getInterfaces(),new DynPrx(tgt));} Use createProxyto make new proxy with same interface as subject
Handing Dynamic Proxies class DynPrx<T>implements InvocationHandler {privateTsubject;private DynPrx(Ttarget) {subject=target; } public static <T> T createProxy(T tgt) { Class actual = tgt.getClass();return (T)Proxy.newProxyInstance(actual.getClassLoader(),actual.getInterfaces(),new DynPrx(tgt)); } Uses Proxyclass in java.lang.reflectto make proxy for tgt
Handing Dynamic Proxies class DynPrx<T> implements InvocationHandler{private Tsubject; // More code will go here /* Magic method used by Java to execute the proxy methods */ public Object invoke(Objectproxy, Method m,Object[] args) throws Exception {return m.invoke(subject, args); }
Handing Dynamic Proxies class DynPrx<T> implements InvocationHandler { private T subject; // More code will go here /* Magic method used by Java to execute the proxy methods */ public Object invoke(Object proxy, Method m,Object[] args) throws Exception { return m.invoke(subject, args); } invokerun for all calls with dynamic proxy. m is instance of actual method called & args were arguments passed in call Object used since can be any return type
Reflection Calls a Method class DynPrx<T> implements InvocationHandler { private T subject; // More code will go here /* Magic method used by Java to execute the proxy methods */ public Object invoke(Object proxy, Method m, Object[] args) throws Exception {return m.invoke(subject, args); } Method.invokecalls method on subjectwith arguments args
Using our Dynamic Proxy abstract class Elect implements Election {public void handleBallot(ElectionUIui) {Election el = DynPrx.createProxy(this);ui.addVoteRecorder(el); ... }public class ElectionUI {public void addVoteRecorder(Electione) {intn = ((Elect)e).choices.find("Prof. Hertz"); ((Elect)e).votes.set(n, 10000);listeners.add(e); } public void ballotChecks() { for (Election e : listeners)e.recordVote(id) }
One Last Requirement to Meet • Forgot requirement for all voting machines • Should have paper receipt to backup results • Copy for system & voter: 2 copies may be better • 4 copies prevents vote buying via complex system • Could instead log votes to secondary server • Or combine approaches to create better method • Which of the design patterns do we use now?
Answer Is Obvious… • Forgot requirement for all voting machines • Should have paper receipt to backup results • Copy for system & voter: 2 copies may be better • 4 copies prevents vote buying via complex system • Could instead log votes to secondary server • Or combine approaches to create better method • Which of the design patterns do we use now? • Mix-and-match options in any order desired • Pattern should be invisible to client code
Proxy Pattern as Decorator • Dynamic Proxies enable easy decoration • Core concept still used by template method • Decorate this by using series of nested proxies • Code in invokeexecuted before calling subject • Parameters & reflection provide all needed data • Can skip call to inner instance like decorator • Within decorator, skip "pseudo-recursive" call • Skip call to invokewhen using dynamic proxy
Proxy Factory To Log Calls class LogPrx<T> implements InvocationHandler{private Tsubject;private LogPrx(Ttarget) {subject = target; }public static <T>TcreateProxy(Ttgt) {Class actual = tgt.getClass();return (T)Proxy.newProxyInstance(actual.getClassLoader(),actual.getInterfaces(),new LogPrx(tgt)); }
Log All Calls class LogPrx<T> implements InvocationHandler{private Tsubject; // Code from last slide goes here… /* Magic method used by Java to execute the proxy methods */ public Object invoke(Objectproxy, Method m,Object[] args) throws Exception {System.out.print(m.getName());System.out.print (Arrays.toString(args));System.out.print (" -> ");Object retVal= m.invoke(subject, args);System.out.println(retVal); return retVal; }
Composing Our Proxies abstract class Elect implements Election {public void handleBallot(ElectionUIui) {Election el = DynPrx.createProxy(this); el = LogPrx.createProxy(el); el = LogPrx.createProxy(el);ui.addVoteRecorder(el); ... }
For Next Class • Last lab due “Friday” so better start working • Start now == more committing acts against man & beast • Should now go on-line to do course evaluation • But still important, not just ratemyprofessor.com • I really appreciate honest feedback & suggestions • Also used by administration to evaluate faculty -----censored-----