Two Kinds of Proxies

When working with proxies, there is a wide array of strategies available to you for implementing them. One strategy is the use of pre-compile-time tools such as those used by CORBA. Also, proxies can be manually written, reflexively driven, or dynamically generated.

Static Proxies

Proxies that are written manually are referred to as static proxies. Static proxies are programmed into the system at compile time. Example 10-2 shows a simple static proxy. Programming static proxies is a just like coding any other class with a couple of new rules:

  • The proxy can never extend the implementation (or vice versa). The proxy and implementation must form a delegation structure in which the proxy delegates to the implementation. This restriction exists because if the proxy simply extended the implementation, a user would be able to cast the proxy to the implementation and bypass the proxy altogether. For example, if you create a proxy to implement a security policy and the user can cast away the proxy, then you would have a huge hole in your security.
  • The user of the proxy should never create the implementation. If the user can create an implementation directly, then he can bypass the proxy and simply use the implementation. For example, the following usage of the proxy from Example 10-2 would be a bad idea because it would bypass any checking code in the proxy:
    package oracle.hcj.proxies;
    public class DemoClientGeneratedProxy {
     public static final void main(final String[] args) {
     SomeClassProxy proxy = new SomeClassProxy(new SomeClassImpl("Fred"));
     proxy.someMethod( );
     proxy.someOtherMethod("Our Proxy works!");
     }
    }
    


    Since there is nothing to prevent a user from ignoring the proxy and going directly to the implementation, proxies should always be obtained from a factory or through calls to other proxies. Furthermore, the implementations should be protected from access by the client.

When writing static proxies, the programmer introduces new code into the proxy to implement the new functionality. For example, you can alter the proxy from Example 10-2 to incorporate the ability to count how many times the methods of the implementation are called. The resulting class is shown in Example 10-4.

Example 10-4. A counting proxy
package oracle.hcj.proxies;
public class SomeClassCountingProxy {
 private final SomeClassImpl impl;
 private int invocationCount = 0;
 public SomeClassCountingProxy(final SomeClassImpl impl) {
 this.impl = impl;
 }
 public int getInvocationCount( ) {
 return invocationCount;
 }
 public void someMethod( ) {
 this.invocationCount++;
 this.impl.someMethod( );
 }
 public void someOtherMethod(String text) {
 this.invocationCount++;
 this.impl.someOtherMethod(text);
 }
}


This static proxy will keep track of the number of times the implementation's methods are invoked. You changed the original proxy and inserted content into the proxy to implement the required functionality. Using the proxy is virtually identical to using the SomeClassProxy object. Here's a modified factory-creation method:

package oracle.hcj.proxies;
public class SomeClassFactory {
 public static final SomeClassCountingProxy getCountingProxy( ) {
 SomeClassImpl impl = new SomeClassImpl(System.getProperty("user.name"));
 return new SomeClassCountingProxy(impl);
 }
}


Just as before, get the proxy from the factory and then use it as if it were the class itself:

package oracle.hcj.proxies;
package oracle.hcj.proxies;
public class DemoCountingProxy {
 public static final void main(final String[] args) {
 SomeClassCountingProxy proxy = SomeClassFactory.getCountingProxy( );
 proxy.someMethod( );
 proxy.someOtherMethod("Our Proxy works!");
  System.out.println("Method Invocation Count = " +
 proxy.getInvocationCount( ));
 }
}


Here, you access the methods in an identical fashion as the last proxy you wrote. However, this method counts the number of invocations to the methods of the implementation. In the emphasized code, you write out the invocation count. The output is shown here:

>ant -Dexample=oracle.hcj.proxies.DemoCountingProxy run_example run_example:
 [java] Robert
 [java] Our Proxy works!
 [java] Method Invocation Count = 2


This two-tier functionality gives you a great deal of power in designing strong apps. You can insert code in between the implementation of an object and the object itself to alter the functionality of the original implementation. Also, you can add more methods to the proxy class that did not exist in the original implementation class. For example, the getInvocationCount( ) method, which does not exist in the original implementation, was added. This technique is known as a decorator pattern. Decorators are especially useful when you want to modify objects whose sources you do not control, such as third-party libraries. However, they can also be useful in creating extended functionality of an object within a particular context, as is done with method counting.

Proxy by Interface

In previous examples, the proxies that you created required that the user know which kind of proxy he wants. This is often not a desirable situation. For example, a distributed program that could be spread across several machines would want to take advantage of a variety of proxies, depending on the location of the implementation. If the implementation is running on the same machine, the program shouldn't have to use the network to talk to the object; if the object is elsewhere on the LAN, then networking is required. However, the user of the implementation is not interested in these details. He simply wants to use the object without worrying about where the actual implementation is. What you need is a way for the factory to give the user the correct proxy based on specific information, such as where the implementation is located within a network. In Example 10-4, you created a proxy that counted the number of times the methods of the object was called. As an example of a proxy that behaves differently based on specific conditions, suppose that your counting proxy may be necessary during debugging but not during the deployment of the app. What you would like to do is give the user the counting proxy when debugging is activated and the noncounting proxy when debugging is turned off. However, the user won't know which proxy he is getting until runtime. Therefore, you need another way for the user to refer to the proxy. Java interfaces are ideally suited to solving such problems. To isolate the implementation details of the proxy, you can use an interface that describes the functionality of the implementation. When you apply this technique to the implementation class from Example 10-2, you get the result in Example 10-5.

Example 10-5. An interface to an implementation
package oracle.hcj.proxies;
public interface SomeClass {
 public abstract void someMethod( );
 public abstract void someOtherMethod(final String text);
}


Now that you have an interface to your implementation, you can enforce this interface by changing SomeClassImpl:

public class SomeClassImpl implements SomeClass {
 // same as before
}


Additionally, you can make the proxy classes implement the interface:

public class SomeClassProxy implements SomeClass {
 // same as before
}
public class SomeClassCountingProxy implements SomeClass {
 // same as before
}


Although the proxy classes implement the interface, this doesn't break the inheritance rule from earlier because the user will have only the proxy, which doesn't inherit from the implementation. If a user gets a proxy and casts it up to the interface, the virtual machine won't have a problem. However, if he tries to cast the interface to the implementation, the built-in RTTI mechanism will slap him with a ClassCastException. Casting an object doesn't change its type; it merely changes the view of its type. An instance of SomeClassProxy remains SomeClassProxy no matter how it is cast. Now that both of the proxies and the implementation are using this new interface, you can create a factory that allows the user to ignore the actual implementation of the proxy itself. This factory is shown in Example 10-6.

Example 10-6. A factory that gives back various proxies
package oracle.hcj.proxies;
public class SomeClassFactory {
 public static final SomeClass getSomeClassProxy( ) {
 SomeClassImpl impl = new SomeClassImpl(System.getProperty("user.name"));
 if (LOGGER.isDebugEnabled( )) {
 return new SomeClassCountingProxy(impl); 
 } else {
 return new SomeClassProxy(impl); 
 }
 }
}


The new factory method simply gives back an object of type SomeClass. Since both of the proxies implement SomeClass, you can give back whichever one you want. In this example, if Log4J is set for debugging, return the proxy that counts invocations; otherwise, return the noncounting proxy. To use the new factory method, the user simply needs to know he is getting an instance of SomeClass. Your new proxy scheme is shown here:

package oracle.hcj.proxies;
public class DemoInterfaceProxy {
 public static final void main(final String[] args) {
 SomeClass proxy = SomeClassFactory.getSomeClassProxy( );
 proxy.someMethod( );
 proxy.someOtherMethod("Our Proxy works!");
 }
}


The user doesn't need to know (or care) if the proxy is counting. You can give him any proxy that conforms to the interface SomeClass. Using interfaces is clearly superior to using concrete classes because it decouples the client from the server object, allowing the developer to insert code between the client and server objects depending on various criteria. In this example, the count of the method invocations in the demo program is not shown. You could, however, check to see whether proxy is an instance of SomeCountingProxy and output the count:

if (proxy instanceof SomeClassCountingProxy) {
 System.out.println(((SomeClassCountingProxy)proxy).getInvocationCount( ));
}


This code would allow you to print the count if the proxy is a counting proxy, or simply skip it if it is a noncounting proxy.

Screenshot

In real-life programs, the client of a proxy rarely needs to access the features of the proxy itself. Normally, third-party tools such as cache managers and network monitors need this extra information. Therefore, it's rare that a client would care which kind of proxy she had received from a factory.


Similarly, you could create additional interfaces that extend the SomeClass interface to implement dynamically returned decorators, each adding new methods that are specific to the proxy classes. Each of the proxy classes would implement the extended interface, which would be used by the clients of the implementation. This is an extremely powerful way to deal with a variety of implementations.

Dynamic Proxies

Screenshot

The concepts in this section depend on the tools available in JDK 1.4. JDK 1.3 and below lack the proxy tools in the java.lang.reflect package.


While coding proxies to objects, you may notice yourself doing the same thing over and over again in a proxy class. For example, for each implementation for which you wanted a counting proxy, you would have to replicate all of the work that you had already done for each new implementation. The problem with this is that all these proxy classes with duplicated code are troublesome to maintain. If your proxy had 1,000 lines of networking code, and a bug was found in just one line, you would have to remember to change that line in each bit of duplicated code, throughout tens, or even hundreds, of additional proxies.

Screenshot

Whenever you see words such as "you have to remember," then a warning light should go off in your head. The problem is that many times we don't remember. When pressed with deadlines, we sometimes forget to do these things, and they bite us later. Also, programmers new to your project may not know they need to remember these constraints. All dependencies in your code should be modeled (and documented), not stored in your head.


To alleviate this problem, you could create helper utility methods that each proxy could call, but you would still be stuck with multiple proxy classes that do essentially the same thing. What you need is a way to implement the method-counting code in one location, and a way to reuse it for any object. Dynamic proxies can do this by using reflection. Dynamic proxies differ from static proxies in that they do not exist at compile time. Instead, they are generated at runtime by the JDK and then made available to the user. This allows the factory to bind an object to many different kinds of implementations without copying or duplicating code.

Invocation handlers

When writing a dynamic proxy, the principal task of the programmer is to write an object called an invocation handler, which implements the InvocationHandler interface from the java.lang.reflect package. An invocation handler intercepts calls to the implementation, performs some programming logic, and then passes on the request to the implementation. Once the implementation method returns, the invocation handler returns its results (along with any exceptions thrown). Example 10-7 shows an invocation handler that implements your method-invocation counting.

Example 10-7. A method-invocation-counting invocation handler
package oracle.hcj.proxies;
public class MethodCountingHandler implements InvocationHandler {
 private final Object impl;
 private int invocationCount = 0;
 public MethodCountingHandler(final Object impl) {
 this.impl = impl;
 }
 public int getInvocationCount( ) {
 return invocationCount;
 }
 public Object invoke(Object proxy, Method meth, Object[] args)
 throws Throwable {
 try {
 this.invocationCount++;
 Object result = meth.invoke(impl, args);
 return result;
 } catch (final InvocationTargetException ex) {
 throw ex.getTargetException( );
 }
 }
}


This invocation handler provides the same functionality as static proxies. However, it uses reflection to do the job. When a user executes a method on the proxy, the invocation handler is called instead of the implementation. Inside the invocation handler, insert code to increment the invocationCount variable and then forward the call to the implementation using the invoke( ) method on the Method object. Once the invocation is complete, the implementation will return a value to the handler. You then pass that value back to the caller.

Screenshot

When writing invocation handlers, be careful of methods that return primitive types. The JDK will wrap primitive types in their corresponding wrapper types to return them from a reflexive invocation. The problem is that your handler can return null, but the actual method being called on the implementation cannot. Therefore, if you try to return null after calling a method that returns a primitive, the proxy class will throw a NullPointerException. This NullPointerException applies to the return value, not to the parameters of the method.


The code inside the invoke( ) method can do a variety of things. In this example, you simply count the invocations of methods. However, you could write an invocation handler that would perform security checks or even implement IIOP protocol to send method calls across the network.

Generated proxy classes

Writing an invocation handler is only the first step in generating a dynamic proxy. Once you have an invocation handler, you must generate a proxy for the users. Furthermore, according to the proxy design pattern, you have to make sure that the proxy looks like the implementation; the user shouldn't be aware of the differences between the proxy and the implementation. You can do this by using a java.lang.reflect.Proxy class in conjunction with your proxy factory. The resulting factory method is shown here:

package oracle.hcj.proxies;
public class SomeClassFactory {
 public static final SomeClass getDynamicSomeClassProxy( ) {
 SomeClassImpl impl = new SomeClassImpl(System.getProperty("user.name"));
 InvocationHandler handler = new MethodCountingHandler(impl);
 Class[] interfaces = new Class[] { SomeClass.class };
 ClassLoader loader = SomeClassFactory.class.getClassLoader( );
  SomeClass proxy = (SomeClass)Proxy.newProxyInstance(loader, 
 interfaces, 
 handler);
 return proxy;
 }
}


In this version of the factory method, SomeClass is an interface implemented by the actual implementation, named SomeClassImpl. This allows you to tell the Proxy class to generate a new proxy that implements the interface SomeClass and uses the invocation handler.

Screenshot

One limitation of this system is that the implementation class must implement the interfaces used in the proxy. Therefore, if the implementation did not implement the interface in the first place and the source code is out of your control, this paradigm won't work.


The Proxy class plays a pivotal role in creating and managing new proxy classes in the virtual machine. Proxy got its enormous power from only four methods:


getInvocationHandler( )

This method gives the caller a reference to the invocation handler used in the proxy given as a parameter.


getProxyClass( )

This is the prime method in the creation of the actual proxy class. It takes an array of interfaces and a class loader as arguments and generates the byte code for the proxy class at runtime. Once the class is generated, it can be instantiated and used. It is then cached and returned the next time the method is called with the same parameters. Since the generation of the proxy class is relatively slow, this improves the performance of proxies significantly.


isProxyClass( )

This method tells you whether the proxy class was generated dynamically. It is used by the security engine to verify that the class is a proxy class.


newProxyInstance( )

This method is a shortcut to calling getProxyClass( ) and then calling newInstance( ) on the resulting class.

Generated proxy classes are required to conform to the following rules:

  • All proxy classes are declared as public and final.
  • All proxy classes extend the class java.lang.reflect.Proxy.
  • When a proxy class is defined, it implements the interfaces stated in the same order as they are in the array.

There are several additional aspects of generated proxy classes of which you should be aware:

  • The unqualified name of proxies is considered undefined, although the prefix $Proxy is generally reserved for proxy classes. This means that you can't depend on references to the class by name. For example, the following code would be dangerous:
    package oracle.hcj.proxies;
    public class DangerousNames {
     public static final void main(final String[] args) {
     SomeClass proxy = SomeClassFactory.getDynamicSomeClassProxy( );
     System.out.println(proxy.getClass( ).getName( ));
     try {
     Class cl = Class.forName("$Proxy0"); // <== Dangerous!
     System.out.println(cl.getName( ));
     } catch (final ClassNotFoundException ex) {
     ex.printStackTrace( );
     }
     }
    }
    


    Since the unqualified name of a proxy is undefined, using the name literally (as was done in the emphasized line) could cause problems. This code may work on one virtual machine and fail on another, as the name may be correct on the first virtual machine, while the other virtual machine may generate $Proxy_SomeClass0 as the name of the proxy class. The best advice is simply not to rely on the names of proxy classes for anything.

  • Proxy classes are just like other classes with respect to reflection. You can use reflection to get a list of their methods and interfaces and then execute them dynamically.
  • The protection domain of Java proxy classes is the same as the protection domain of the Java bootstrap classes. This means that proxy classes can access all permissions in the JDK.
    Screenshot

    A discussion of protection domains is far outside the scope of this tutorial. For more information on protection domains, check out Java Security by Scott Oaks (Oracle).


  • Proxy classes are generated with a single constructor that takes a single argument of type InvocationHandler. This allows you to create a new proxy if the proxy class object is already using the newInstance( ) method.
Using dynamic proxies

Now that you have your dynamic proxy class, you can use it in a new method:

package oracle.hcj.proxies;
public class DemoDynamicProxy {
 public static final void main(final String[] args) {
 SomeClass proxy = SomeClassFactory.getDynamicSomeClassProxy( );
 proxy.someMethod( );
 proxy.someOtherMethod("Our Proxy works!");
 } }


Using the proxy class is virtually identical to using the static proxy classes. However, there are a couple of important differences. First, the implementation of the proxy is generated by the Proxy class. Second, to get the method invocation count of the proxy, you would have to fetch the invocation handler and then ask the invocation handler for the count:

InvocationHandler handler = Proxy.getInvocationHandler(proxy);
if (handler instanceof MethodCountingHandler) {
 System.out.println(((MethodCountingHandler)handler).getInvocationCount( ));
}


The method Proxy.getInvocationHandler( ) is used to fetch the invocation handler from the proxy. You then make sure that the handler is in fact a MethodCountingHandler; remember that any invocation handler could have been used. Finally, output the invocation count.

      
Comments