How to implement Dynamic Proxy Design Pattern in Java ?.


Lets look at the what Dynamic Proxy Design Pattern does for us :




Program to demonstrate how to implement Dynamic Proxy Design Pattern in Java.


Click here to download complete source code 


Step 1: Creation of Interface

package com.hubberspot.designpatterns.proxy.example;

// Create a interface Developer having
// few getters and setters. See below ...

public interface Developer {

 String getName(); 
 String getSalary();
 String getRole();
 int getRating();


 void setName(String name); 
 void setSalary(String salary);
 void setRole(String role); 
 void setRating(int rating);
}




Step 2 : Creation of Implementation class

package com.hubberspot.designpatterns.proxy.example;

public class DeveloperImpl implements Developer {

 // Few properties and respective 
 // getters and setters in the 
 // interface 
 String name;
 String salary;
 int rating;
 String role;


 @Override
 public String getName() {
  return name;
 }

 @Override
 public String getSalary() {
  return salary;
 }

 @Override
 public String getRole() {
  return role;
 }

 @Override
 public int getRating() {
  return rating;
 }

 @Override
 public void setName(String name) {
  this.name = name;    
 }

 @Override
 public void setSalary(String salary) {
  this.salary = salary;
 }

 @Override
 public void setRole(String role) {
  this.role = role;
 }

 @Override
 public void setRating(int rating) {
  this.rating = rating;
 }

}



Step 3 : Creation of Dynamic proxie as Developer Invocation Handler

package com.hubberspot.designpatterns.proxy.example;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

// Make a proxie as how methods on Developer calls as per the
// developer.
public class DeveloperHandling  implements InvocationHandler {

 // having Developer as a instance variable
 Developer employee;

 // Constructor of class setting the value of the
 // Developer instance variable
 public DeveloperHandling(Developer employee) {
  this.employee = employee;
 }

 // InvocationHandler interface has a method by name
 // invoke which returns back an Object. It works on 
 // the principle of reflection. Each time a call is 
 // made by Developer on its setter and getter this
 // method will be called first.
 // This method takes in three arguments : 
 // 1. Dynamically created proxy object 
 // 2. Method and information regarding the method which 
 // needs to be called. 
 // 3. Plus what arguments called method takes to fulfil
 // the calling process.
 @Override
 public Object invoke(Object proxy, Method method, Object[] args)
   throws IllegalAccessException {

  try {

   // Method class has a method by getName() , which returns
   // back the method name which is called by the Developer.

   if(method.getName().startsWith("get")) {

    // Method class has a method by name invoke().
    // This method invokes employee methods and passing 
    // the aruments to it, based on the if condition.
    return method.invoke(employee, args);

   }

   // In order to set restriction on developer to 
   // not able to change state of role, salary and rating
   // if condition on fulfillment throws IllegalAccessException
   // because a developer has no right to set his salary,
   // role and rate himself. It is duty of his manager to 
   // which he reports
   else if (method.getName().equals("setRole")) {
    throw new IllegalAccessException();
   }
   else if (method.getName().equals("setSalary")) {
    throw new IllegalAccessException();
   }
   else if (method.getName().equals("setRating")) {
    throw new IllegalAccessException();
   }

  } 
  catch(InvocationTargetException e) {
   e.printStackTrace();
  }


  return null;
 }

}




Step 4 : Creation of Dynamic proxie as Managers Invocation Handler

package com.hubberspot.designpatterns.proxy.example;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

// same explanation as given in DeveloperHandling.java class
// above
public class ManagersHandling implements InvocationHandler {

 Developer employee; 

 public ManagersHandling(Developer employee) {
  this.employee = employee;
 }

 @Override
 public Object invoke(Object proxy, Method method, Object[] args)
   throws IllegalAccessException {

  try { 

   if(method.getName().startsWith("get")) {

    return method.invoke(employee, args);

   }
   else if(method.getName().startsWith("setName")) {

    throw new IllegalAccessException();

   }
   else if(method.getName().startsWith("set")) {

    return method.invoke(employee, args);

   }

  }
  catch (InvocationTargetException e) {
   e.printStackTrace();
  }


  return null;
 }

}



Step 5: Test class for creating Dynamic Proxies and running the code.

package com.hubberspot.designpatterns.proxy.example;

import java.lang.reflect.Proxy;
import java.util.HashMap;

public class HRMTest {

 // Create a HashMap to store employee object as a 
 // name value pair
 HashMap developer = new HashMap();

 public HRMTest() {
  // Constructor creates a new Developer by 
  // giving it a few properties.
  Developer dinesh = new DeveloperImpl();
  dinesh.setName("Dinesh Varyani");
  dinesh.setSalary("25000");
  dinesh.setRating(7);
  dinesh.setRole("Senior Developer");
  developer.put("Dinesh", dinesh);

 }

 public static void main(String[] args) {

  // main method after creating HRMTest object 
  // calls test() method.
  HRMTest hrmTest = new HRMTest();
  hrmTest.test();

 }

 public void test() {

  // Initially if Proxy Design Pattern hadn't been implemented Developer
  // and Manager can all change state of Developer/employee properties.
  System.out.println("---------------------------------------------------");
  System.out.println("Let's test Developer perspective .....\n");

  // Lets look at developer perspective what he has restriction
  // on him after implementing Proxy Design pattern.
  Developer dinesh = (Developer)developer.get("Dinesh");
  Developer developerProxy = getDeveloperProxy(dinesh);

  System.out.println("Name of the developer : " + developerProxy.getName());

  // He cannot set his rating, salary and role. An exception will be
  // thrown which will print following message in sysouts
  try{
   developerProxy.setRating(10);
  }
  catch(Exception e) {
   System.out.println("Developer cant provide rating to itself");
  }

  try{
   developerProxy.setSalary("100000");
  }
  catch(Exception e) {
   System.out.println("Developer increase or set salary to itself");
  }

  try{
   developerProxy.setRole("Manager");
  }
  catch(Exception e) {
   System.out.println("Developer cannot change its role in company\n");
  }

  System.out.println("---------------------------------------------------");

  System.out.println("Let's test Managers perspective .....\n");

  // Lets look at the Managers perspective now as what it does to developer
  // object 
  dinesh = (Developer)developer.get("Dinesh");

  Developer managerProxy = getManagerProxy(dinesh);

  System.out.println("Name of the developer : " + managerProxy.getName());

  System.out.println("Set salary of the employee : "); 
  managerProxy.setSalary("15000");

  System.out.println("Salary of the developer : " + managerProxy.getSalary());

  // He cannot change the name of the developer. Rest he can change i.e
  // salary, role and rating.
  try{
   managerProxy.setName("Mangesh Virani");
  }
  catch(Exception e) {
   System.out.println("Manager cant change or set name of developer");
  }

  System.out.println("---------------------------------------------------");


 }


 // In order to create Dynamic Proxy we have to apply following steps
 // in java 
 // This method takes in a Developer object (real) and returns
 // back the proxy for it. It returns a Developer which acts as
 // proxy.
 public Developer getDeveloperProxy(Developer employee) {

  // To create a Dynamic Proxy we have to call
  // newProxyInstance() static method of class Proxy. 
  // It takes three arguments : 
  // 1. Class Loader for our real object.
  // 2. Set of interfaces proxy needs to implement.
  // 3. A new object of our DeveloperHandling invocation
  // handler. It takes in the real object and returns
  // us back with proxy object. 

  return (Developer) Proxy.newProxyInstance(
    employee.getClass().getClassLoader(), 
    employee.getClass().getInterfaces(), 
    new DeveloperHandling(employee));

 }

 public Developer getManagerProxy(Developer employee) {
  // Same as above. Instead of Developer now it returns 
  // an proxy on Managers Handling mechanism.
  return (Developer) Proxy.newProxyInstance(
    employee.getClass().getClassLoader(), 
    employee.getClass().getInterfaces(), 
    new ManagersHandling(employee));

 }

}



Click here to download complete source code

Output of the program :