Object A....present sir!!(Proxy object ;))

 

I was really busy in last few days working on frameworks like spring and hibernate. While working on that I realized that like Java is a heart of Web development these days. Proxy pattern is also heart of these frameworks that creates objects at run time and map DB values to object attributes at run time.  I wanted to understand each and every aspect of Proxy design pattern and wanted to implement them to see how they actually work. So this is the real motivation behind this article. From couple of weeks it was in coming soon mode! I was busy with some hectic work.

So here we are with Proxy pattern. Proxy is the word that I have used mostly when I was in school/college ;) I am sure most of us have done that. So let us take an example of a class which has 10 students and teacher is asking for the attendance. One of your friend who has always favored you in all the circumstances is absent from the class and you know that if he won’t have attendance today he will be in trouble so what you will do in that case? You will make a proxy present on behalf of your friend and the magic will be your teacher will not come to know that it was you instead of your friend. Now that’s your talent ;)

This is how proxy works in Java as well.

What is proxy design pattern?

Proxy pattern is used when you want to give access to an interface or a simple object on behalf of a complex object.

Various Implementations of Proxy design Patterns:

  1. Remote Proxy
  2. Lazy loading
  3. Access Proxy
    As mentioned above there are multiple implementations of Proxy pattern. We will go through each of them with example.


Remote Proxy:

This implementation uses RMI to implement proxy pattern. If you are not comfortable with RMI have a look at Crash Course in Java RMI. This is used when we are using an object remotely. For example on machine A we have an implementation of Cryptography which encrypts and decrypts a message string. We are passing a message from A to machine B which does not have any mechanism to decrypt that message the only thing machine B can do is remotely call Decrypt object from A and use its method to decrypt that message as shown below.

This remote object acts as a proxy object which is basically a stub for the machine B and it appears to be original object to machine B that is the magic of RMI in java. This is where serialization also comes in to picture objects which will be used as remote objects are recommended to be serialized.


We have a simple example where we have an interface called IPattern.java and it has a method specification getPatternName( ). ProxyPattern.java implements this interface and returns “Proxy Patern” as name of the pattern in getPatternName method implementation.

ProxyServer.java class acts as a server for Remote machine. It binds the ProxyPattern object with RMI registry and provides access to the client.

ProxyClient.java accesses this object remotely using RMI and calls the method on this stub. Client object will never now that it has access to the stub of original object.

package com.pawan.remoteproxy.server;  

import java.rmi.Remote;  

/**  
* This interface will use RMI to use proxy.  
* @author Pawan Chopra  
*  
*/  
public interface IPattern extends Remote{  

/**  
* This returns name of the pattern.  
* @return  
*/  
public String getPatternName();  

}  
package com.pawan.remoteproxy.server;  
import java.rmi.RemoteException;  
import java.rmi.server.UnicastRemoteObject;  

/**  
* This class will implement <a href="mailto:{@link">{@link</a> IPattern} to act as a Remote class and  
* extends <a href="mailto:{@link">{@link</a> UnicastRemoteObject} which will perform all the  
* required tasks to make this class work remotely.  
*  
* @author Pawan Chopra  
*  
*/  
public class ProxyPattern extends UnicastRemoteObject implements IPattern{  

/**  
* This is a default constructor but we have to override it  
* as we have to throw <a href="mailto:{@link">{@link</a> RemoteException} becuase super  
* class does the same.  
*  
* @throws RemoteException  
*/  
protected ProxyPattern() throws RemoteException {  
super();  
}  

@Override  
public String getPatternName() {  
return "Proxy Pattern";  
}  

}  
package com.pawan.remoteproxy.server;  

import java.net.MalformedURLException;  
import java.rmi.AlreadyBoundException;  
import java.rmi.Naming;  
import java.rmi.RemoteException;  

/**  
* This acts as a server which binds the remote class  
* and register in the rmi registry so that clients can  
* access them remotely. A basic overview will be good  
* for you in case you want to understand RMI.  
*  
* @author Pawan Chopra  
*  
*/  
public class ProxyServer {  

public static void main(String[] args) {  

ProxyPattern proxyPattern = null;  
try {  
proxyPattern = new ProxyPattern();  
} catch (RemoteException e) {  
System.err  
.println("Remote exception thrown while creating object of ProxyPattern!");  
}  
try {  
//Bind the object and register in rmi registry  
Naming.rebind("pattern", proxyPattern);  
} catch (MalformedURLException e) {  
System.err.println("Malformerd URL Excepion thrown while binding!");  
} catch (RemoteException e) {  
System.err.println("Remote Exception thrown while binding");  
}  
}  

}  
package com.pawan.remoteproxy.client;  
import java.rmi.Naming;  

import com.pawan.remoteproxy.server.IPattern;  
import com.pawan.remoteproxy.server.ProxyPattern;  

/**  
* This class acts as client for Remote Proxy object.  
* @author Pawan Chopra  
*  
*/  
public class ProxyClient{  

public static void main(String[] args) throws Exception{  

//Look up in the rmi registry and fetch the proxy object.  
IPattern pattern = (ProxyPattern)Naming.lookup("rmi://127.0.0.1/proxyPattern");  
System.out.println(pattern.getPatternName());  

}  
}  

Virtual Proxy

This is basically an example of lazy loading. I am sure this term is known to everybody. So what is lazy loading by the way it says that we fetch/create something only when it is required. Till then show something fake to the end user this is all about lazy loading.

Virtual proxy helps lazy loading to show that fake thing. Not really fake but yes a stub of real object. As you can see above we have an interface called IStore which provides a facility to fetch address of a Store.

BookStore object is implementing this interface. Now it may be possible that we try to fetch address from the DB or the web services which may take time.  So we will use a proxy implementation BookStoreProxy to respond to the user.

You can see that BookStoreProxy uses composition with BookStore and use original object to respond the real data.  In our when server is trying to fetch data from the DB or web services proxy object is used to respond the client which says user to have patience and wait for the results.

This is a very simple example of lazy loading in real world we have ORM tools like hibernate and spring using lazy loading concept.

* * * * * * * * * * * * * * * * * * * * * * * * * * * *

package com.pawan.virtualproxy;  
/**  
* This interface defines a store.  
* @author Pawan Chopra  
*  
*/  
public interface IStore {  
/**  
* This method returns Address of Store.  
* @return  
*/  
public String getStoreAddress();  

}  
[/sourcecode]  
[sourcecode language="css"]package com.pawan.virtualproxy;  

/**  
* @author Pawan Chopra  
*  
*/  
public class BookStore implements IStore {  

String address;  
@Override  
public String getStoreAddress(){  
//Call a private method  
return fetchAddressFromDBorURL();  
}  
private String fetchAddressFromDBorURL(){  

/*  
* This is just an inner class to make it wait for some time.  
* In real time this will be fetching data from Database or  
* from URL.  
*  
*/  
Thread t = new Thread(){  
public void run(){  
try {  
Thread.sleep(10000);  
} catch (InterruptedException e) {  
System.err.println("Unable to sleep at this time!");  
}  
address = "Sector -63, Noida";  
}  
};  
t.start();  

return address;  
}  
}  
[/sourcecode]  
[sourcecode language="css"]package com.pawan.virtualproxy;  

/**  
* Proxy object for BookStore.  
* @author Pawan Chopra  
*  
*/  
public class BookStoreProxy implements IStore {  
//Composition  
private BookStore bookStore;  

public BookStoreProxy(BookStore bookStore){  
this.bookStore = bookStore;  
}  

@Override  
public String getStoreAddress(){  

/*  
* This is where lazy loading comes in to picture.  
* see below the code we have a while loop which  
* inform user that data is getting loaded so until  
* data is loaded we have used to proxy object to  
* serve the user.  
*/  
while(bookStore.getStoreAddress()==null){  
try {  
Thread.sleep(700);  
} catch (InterruptedException e) {  
System.err.println("Unable to sleep at this time!");  
}  
System.out.println("Trying to locate the store...Please wait!");  
}  

return bookStore.getStoreAddress();  

}  

}  
package com.pawan.virtualproxy;  

public class ProxyRunner {  
/**  
* @param args  
*/  
public static void main(String[] args) {  

IStore store = StoreFactory.getBookStore();  
System.out.println(store.getStoreAddress());  

}  
}  
[/sourcecode]  
[sourcecode language="css"]package com.pawan.virtualproxy;  
/**  
* Factory class to return instance of IStore.  
* @author Pawan Chopra  
*  
*/  
public class StoreFactory {  
/**  
* Factory method  
* @return  
*/  
public static IStore getBookStore(){  
return new BookStoreProxy(new BookStore());  
}  

}  

Access Proxy

Proxy pattern is very useful for Security process. Once again it uses reflection to check the access permissions according to the logic.  For example as shown above we have an interface ITemperature and we have an implementation for this. This has two methods one to set temperature and another one is used to get temperature.

Access permission is as below:

**Role** **Permission**
Manager Set and Get temperature
Developer Get temperature

For this we have a role interface which has an implementation.

The heart of this example is AccessProxy class which controls the permissions part. In the invoke() method it verifies the role and throws exception accordingly.

package com.pawan.accessproxy;  
public interface ITemperature {  

public void setTemperature(int temp);  
public int getTemperature();  
}  
package com.pawan.accessproxy;  

/**  
*  
* @author Pawan Chopra  
*  
*/  
public class TemperatureImpl implements ITemperature {  

private int temp = 10; //default value as we are not using caching  

@Override  
public void setTemperature(int temp) {  
this.temp = temp;  
}  

@Override  
public int getTemperature() {  
return this.temp;  
}  

}  
package com.pawan.accessproxy;  

/**  
* This interface defines roles based on those roles  
* read/write permission will be granted.  
* @author Pawan Chopra  
*  
*/  
public interface Role {  

String MANAGER = "Manager";  
String DEVELOPER = "Developer";  

public String getType();  
}  
[/sourcecode]  
[sourcecode language="css"]  
package com.pawan.accessproxy;  

public class RoleImpl implements Role {  

String type;  

public RoleImpl(String type) {  
this.type = type;  
}  

/**  
* @return the type  
*/  
public String getType() {  
return type;  
}  

}  
package com.pawan.accessproxy;  

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

/**  
* This class show an example of Dynamic Proxy using reflection.  
* @author Pawan Chopra  
*  
*/  
public class AccessProxy implements InvocationHandler {  

ITemperature obj;  
Role role;  

public AccessProxy(ITemperature obj,Role role) {  
this.obj = obj;  
this.role = role;  
}  

/**  
* Kind of factory method to return proxy object.  
*  
* @param obj  
* @param interfaces  
* @param role  
* @return  
*/  
public static Object newInstance(ITemperature obj, Class[] interfaces,Role role) {  
return java.lang.reflect.Proxy.newProxyInstance(obj.getClass()  
.getClassLoader(), interfaces, new AccessProxy(obj,role));  
}  

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

String method_name = method.getName();  

if(method_name.startsWith("set")){  
if(role.getType().equals( Role.MANAGER )){  
//invoke method on the proxy object  
method.invoke(obj, args);  
}  
else{  
//If not a manager throw Access exception.  
throw new IllegalAccessException("Must be a Manager to invoke this method.");  
}  
return null;  
}  
else{  
return method.invoke(obj, args);  
}  

} catch (InvocationTargetException e) {  
System.err.println("Problem occucred while invoking a method"+e.getStackTrace()[0].getLineNumber());  
}  
return null;  
}  

}  
package com.pawan.accessproxy;  

/**  
* Access Proxy Tester  
* @author Pawan Chopra  
*  
*/  
public class AccessProxyRunner {  

/**  
* @param args  
*/  
public static void main(String[] args) {  

Role manager = new RoleImpl(Role.MANAGER);  
Role developer = new RoleImpl(Role.DEVELOPER);  

//Get Temperature object from factory.  
ITemperature temp_common = TemperatureFactory.getTemperature();  

ITemperature proxy_dev = (ITemperature) AccessProxy.newInstance(  
temp_common, new Class[] { ITemperature.class }, developer);  

try {  
//Let us try to set using developer role. Its not  
//required to handle exception here I have done this just for verification.  
proxy_dev.setTemperature(10);  
} catch (Exception e) {  
//Just trying to see what getStackTrace gives me(really great stuff).  
System.err.println("Not able to access "  
+ e.getStackTrace()[0].getMethodName() + " method from "  
+ e.getStackTrace()[1].getClassName() + " at Line number "  
+ e.getStackTrace()[1].getLineNumber());  
}  

System.out.println("Developer Access:- " + proxy_dev.getTemperature());  

ITemperature proxy_manager = (ITemperature) AccessProxy.newInstance(  
temp_common, new Class[] { ITemperature.class }, manager);  

//Let us try with Manager now.  
proxy_manager.setTemperature(100);  

System.out.println("Manager access:- "+ proxy_manager.getTemperature());  
System.out.println("Recheck Developer Access:- "+ proxy_dev.getTemperature());  

}  

}  
package com.pawan.accessproxy;  

/**  
* Temperature Factory  
* @author Pawan Chopra  
*  
*/  
public class TemperatureFactory {  

public static ITemperature getTemperature(){  
return new TemperatureImpl();  
}  

}  

This is all from my side on proxy pattern I know this is not the best but keep looking in to this I will be updating it with much more clear content but still I hope this will help you guys. I will be looking for your feedback.

Share on : Twitter, Facebook or Google+