8 min read

Proxy—A Primer

Wikipedia defines Proxy as:

Proxy may refer to something which acts on behalf of something else.

In the software a proxy is a substitute for a target instance and is a general pattern which appears in many other patterns in different variants.

Proxy Design Pattern

A proxy is a surrogate class for the target object. If a method call has to be invoked in the target object, it happens indirectly through the proxy object. The feature which makes proxy ideal for many situations is that the client or the caller is not aware that it is dealing with the proxy object. The proxy class is shown in the following figure:

Service Oriented Java Business Integration

In the above figure, when a client invokes a method target towards the Target service, the proxy intercepts the call in between. The proxy also expose a similar interface to the target, hence the client is unaware of the dealing with the proxy. Thus the proxy method is invoked. The proxy then delegates the call to the actual target since it cannot provide the actual functionality. When doing so, the proxy can provide call management towards the actual method. The entire dynamics is shown in the following figure:

Service Oriented Java Business Integration

A proxy is usually implemented by using a common, shared interface or super class. Both the proxy and the target share this common interface. Then, the proxy delegates the calls to the target class.

JDK Proxy Class

JDK provides both the class Proxy and the interface InvocationHandler in the java.lang.reflect package, since version 1.3. Using JDK Proxy classes, you can create your own classes implementing multiple interfaces of your choice, at run time.

Proxy is the super class for any dynamic proxy instances you create at run time. Moreover, the Proxy class also accommodates a host of static methods which will help you to create your proxy instances. getProxyClass and newProxyInstance are two such utility methods.

The Proxy API is listed in the following in brevity:

package java.lang.reflect;
public class Proxy implements java.io.Serializable
{
protected InvocationHandler h;
protected Proxy(InvocationHandler h);
public static InvocationHandler getInvocationHandler(Object proxy)
throws IllegalArgumentException;
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
throws IllegalArgumentException;
public static boolean isProxyClass(Class<?> cl);
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler h)
throws IllegalArgumentException
}


In the above code, you can invoke the Proxy.getProxyClass with a class loader and an array of interfaces for which you need to proxy, to get a Class instance for the proxy. Proxy objects have one constructor, to which you pass an InvocationHandler object associated with that proxy. When you invoke a method on the proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler. Let us also look at the InvocationHandler API reproduced as follows:

package java.lang.reflect;
public interface InvocationHandler
{
Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}

We need to implement this interface and provide code for the invoke method. Once you get a Class instance for the proxy by invoking the Proxy.getProxyClass with a class loader and an array of interfaces for which you need to proxy to. Now, you can get a Constructor object for this proxy from the Class instance. On the constructor you can use newInstance (passing in an invocation handler instance) to create the proxy instance. The created instance should be implementing all the interfaces that were passed to getProxyClass. The steps are shown in the following code:

InvocationHandler handler = new SomeInvocationHandler(...);
Class proxyClazz = Proxy.getProxyClass(Blah.class.getClassLoader(),
new Class[] {Blah.class});
Blah blah = (Blah) proxyClazz.getConstructor(new Class[] {
InvocationHandler.class }).newInstance(new Object[]
{handler});

There is also a shortcut to get a proxy object. You can invoke Proxy.newProxyInstance, which takes a class loader, an array of interface classes, and an invocation handler instance.

InvocationHandler handler = new SomeInvocationHandler(...);
Blah blah = (Blah) Proxy.newProxyInstance(Blah.class.
getClassLoader(),new Class[] {Blah.class},
handler);

Now you can invoke methods on the proxy object during which these method invocations are turned into calls on to the invocation handler’s invoke method is shown here:

blah.interfaceMethod();

Sample JDK Proxy Class

We will now write some simple code to demonstrate how you can write your own proxies at run time, for your interface classes.

As a first step, if you haven’t done it before, edit examples.PROPERTIES, and change the paths there to match your development environment.

We will now look at the source code that can be found in the folder ch13JdkProxysrc.

The files are explained here:

ch13JdkProxysrcSimpleIntf.java
public interface SimpleIntf
{
public void print();
}

SimpleIntf is a simple interface with a single method print. print does not accept any parameters and also does not return any value. Our aim is that when we invoke methods on the proxy object for SimpleIntf, the method invocation should be turned into calls to an invocation handler’s invoke method. Let us now define an invocation handler in the following code:

ch13JdkProxysrcSimpleInvocationHandler.java

import java.lang.reflect.InvocationHandler;
import java.io.Serializable;
import java.lang.reflect.Method;
public class SimpleInvocationHandler implements InvocationHandler,
Serializable
{
public SimpleInvocationHandler(){}
public Object invoke(final Object obj, Method method,
Object[] args) throws Throwable
{
if (method.getName().equals("print") && (args == null
|| args.length == 0))
{
System.out.println("SimpleInvocationHandler.invoked");
}
else
{
throw new IllegalArgumentException("Interface method does
not support param(s) : " + args);
}
return null;
}
}

Since SimpleIntf.print() does not accept any parameters and also does not return any value, in the invoke method of SimpleInvocationHandler, we double check the intention behind the actual invoker. In other words, we check that no parameters are passed and we return null only.

Now, we have all the necessary classes to implement a proxy for SimpleIntf interface. Let us now execute it by writing a Test class.

ch13JdkProxysrcTest.java

import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
public class Test
{
public static void main(String[] args)
{
InvocationHandler handler = new SimpleInvocationHandler();
SimpleIntf simpleIntf = (SimpleIntf)Proxy.newProxyInstance
(SimpleIntf.class.getClassLoader(),new Class[] { SimpleIntf.
class }, handler);
simpleIntf.print();
}
}



The wiring of the above described interfaces and classes are better represented in the UML class diagram in the following figure:

Service Oriented Java Business Integration

The above figure shows the relationship between various classes and interfaces in the sample. $Proxy0 class represents the actual proxy class generated on the fly and as you can deduce it from the class diagram. $Proxy0 is a type of our interface (SimpleIntf).

To build the sample, first change directory to ch13JdkProxy and execute ant as shown here:

cd ch13JdkProxy
ant

The command ant run will execute the Test class which will print out the following in the console:

Service Oriented Java Business Integration

ServiceMix JBI Proxy

Java proxies for the JBI endpoints can be created in ServiceMix using JSR181 components. For this, the requirement is that the JBI endpoints should expose a WSDL.

A jsr181:endpoint takes a value for the serviceInterface attribute. The JBI container will be able to generate the WSDL out of this serviceInterface. Thus, if we have a jsr181:endpoint exposing service to the JBI bus, it is possible to provide a proxy for that service too.

The basic configuration for defining a JBI proxy is shown as follows:

<jsr181:proxy id="proxyBean"
container="#jbi"
interfaceName="test:HelloPortType"
type="test.Hello" />

Once a proxy is defined, the same can then be referenced from your client bean or from one of your components. The proxied JBI endpoint can then be invoked just like a normal POJO.

If you want to define a JBI proxy within a SU, you can follow the configuration given as follows:

<jsr181:endpoint annotations="none"
service="test:echoService"
serviceInterface="test.Echo">
<jsr181:pojo>
<bean class="test.EchoProxy">
<property name="echo">
<jsr181:proxy service="test:EchoService"
context="#context"
type="test.IService" />
</property>
</bean>
</jsr181:pojo>
</jsr181:endpoint>

Let us now look into a few examples to make the concept clearer.

JBI Proxy Sample Implementing Compatible Interface

First, we will create a JBI proxy implementing an interface compatible with the target service. Then, in place of the target service we will use the proxy instance, so that any calls intended for the target service will be first routed to the proxy. The proxy in turn will delegate the call to the target service. The structural relationship between various classes participating in the interaction is shown in the following figure:

Service Oriented Java Business Integration

Here, EchoProxyService is the class which we later expose in the JBI bus as the service. This class implements the IEcho interface. In order to demonstrate the proxy, EchoProxyService doesn’t implement the service as such, instead depends on the JbiProxy derived out of another class TargetService. The TargetService contains the actual service code. As you can see, both the EchoProxyService and the TargetService implement the same interface.

Proxy Code Listing

The codebase for the sample is located in the folder ch13JbiProxy1_CompatibleInterface1_JsrProxysrc.

This folder contains an interface IEcho and two other classes implementing the IEcho interface namely EchoProxyService and TargetService. These classes are explained here:

  • IEcho.java: The IEcho interface declares a single method echo which takes a String parameter and returns a String.
  • public interface IEcho
    {
    public String echo(String input);
    }
  • EchoProxyService.java: EchoProxyService is a convenient class which will act as mechanism for routing requests to the JBI proxy. Moreover, EchoProxyService implements the above interface IEcho.
  • public class EchoProxyService implements IEcho
    {
    private IEcho echo;
    public void setEcho(IEcho echo)
    {
    this.echo = echo;
    }
    public String echo(String input)
    {
    System.out.println("EchoProxyService.echo. this = " + this);
    return echo.echo(input);
    }
    }
  • TargetService.java: TargetService also implements the interface IEcho. TargetService is supposed to be our target service, and we will be generating a JBI proxy for the TargetService.
  • public class TargetService implements IEcho
    {
    public String echo(String input)
    {
    System.out.println("TargetService.echo : String. this = " +
    this);
    return input;
    }
    }

LEAVE A REPLY

Please enter your comment!
Please enter your name here