Posts tagged ‘proxy’

This blog is a contitunation of my previous entry (polish only sorry) in which I presented a solution for hiding certain operations on a collection using jdk’s dynamic proxy mechanism. It consited of MethodInterceptr which checked if specific method was called and in such a case it reported and error using RuntimeException.

With this entry I’d like to present a different approach using google collection ForwardingObjects. It’s parent for all types of wrappers – one for each collection type and the advantage of using wrapper is that hey’re all designed as abstract classes implementing interface for given type of Collection, in case of Set it’s ForwardingSet (to continue older example) and the only thing you need to do as implementor is to telli wrapper how it can find its delegate by providing a delegate method.

Below you can find previous example rewritten to use ForwardingSet with disabled clear method. Last but not least – this version is waaay much cleaner 🙂 and you also let compiler do its job – if you check the previous post you’ll notice that there are two versions of this solution. The original one contained a but because I made a typo and the code checks for call to clean method instead of clear…

import java.util.Set;
import com.google.common.collect.ForwardingSet;

class StructElement3 {

	private class ForwardingSetNoClear extends ForwardingSet<String> {

		private Set<String> delegate;
		public ForwardingSetNoClear(Set<String> delegate) {
			this.delegate = delegate;
		}

		@Override
		protected Set<String> delegate() {
			return delegate;
		}

		@Override
		public void clear() {
			throw new UnsupportedOperationException("Cannot call clear");
		}
	}

	public StructElement3(Set<String> obj) {
		Set<String> forwardingSet =  new ForwardingSetNoClear(obj);

		// yeah yeah keep talking...
		forwardingSet.clear();
	}

}

Problem description

Imagine you have a project with hierarchical data structure with 4 levels, where 1st level serves as reference data for 2nd and so on. So your task as a developer is to present this on a web form with a checkbox for each value, where „checked” means that it has its own value and „unchecked” means that value of such a field should be taken from it’s parent, with exception for 1st level, which should use only its own values. Furthermore the DTO used for form should pass its state into remote EJB.

Requirements

So let’s summarize it as requirements:

I want to be able to bind a command object with pair of fields – one used for remote EJB and one for determining if field is available on this level. In case field is not available remote EJB object should be passed a null value.

Solution discussion

Simple if/else

The easiest solution is to use regular if/else block and in case field is not available set null passed value otherwise, eg:


if (myCommand.isFieldAvailable()) {
   myRemote.setField(myCommand.getField());
} else {
   myRemote.setField(null);
}

It does the job but it’s a bit of an overhead when you have 20 fields – all 100 lines look alike:

  • check if field is available
  • pass its value to ejb
  • set null otherwise

An experienced OOP developer, which I’m sure you are, sees a needless repetition here and it’s obvious that there’s got to be a better way.

Reflection

Another apporach is to use reflection with property names passed as strings and a helper method which retrieves these using reflection and applies them accrodingly, eg:


fromCommandToEJB("field", command, ejb);

Internally this method will encapsulate logic for checking if available flag is set and reacts to it. This version is much better but it still has one flaw – property name is passed as string and compiler will not warn you when any change in the interface takes place.

Delegating proxy

Proxy may sound a bit intimidating but cglib’s Ehnancer makes it very easy – the only requirement is that you can’t use final classes.

So the work-horse of this solution is MethodInterceptor that has 3 tasks:

  1. Intercept call to a method
  2. Determine if call should be handled (method should be a JavaBean getter).
  3. Handle supported method call (find suffixed method and execute it in order to check what value should be returned).

The first point is handled by cglib internally, so we’re not going to spend any more time on it.

Second point is the decission making part – which  is a slightly modified version of isGetter method presented by Jakob Jenkov in his article on reflection. We’re going to intercept both get and is methods but exclude the ones ending with Available suffix and instead of returning a boolean our method returns a String where null means that method should not be handled.

	private String getHandledPropertyName(Method method) {
		String methodName = method.getName();
		if (!(methodName.startsWith("get") ||
			(methodName.startsWith("is") &&
			!methodName.endsWith(suffix)))) {
			return null;
		}
		else if (method.getParameterTypes().length != 0 ||
			void.class == method.getReturnType()) {
			return null;
		}
		else if (methodName.startsWith("get")) {
			return methodName.substring(3);
		} else {
			return methodName.substring(2);
		}
	}

As you can see returned String is important so we can have decission making (get/is prefix) and propoperty name reading (everything following is/get prefix).

There is a small overhead – every property needs to have an isAvailable method, which in case of compound properties means that each call must be redirected to the „real” checker.

Let’s try an example here – your bean contains start/endDate method so endDate is not valid without startDate, which means that there should be a common method checking if both dates are set and only afterwards passing it for further processing but with proxy you need to have isStartDateAvailable and isEndDateAvailable which might make code analysis a bit harder, so remember to use proper comments to make others work easier.

Third point is very simple – for given property name, find correspoint isAvailable method, check its return value and either call original method, passing its return value or return null.

	private Object handleGetter(Method method, String propertyName) throws Throwable {
		String conditionPropertyName = StringUtils.uncapitalize(propertyName) + suffix;
		PropertyDescriptor conditionDescriptor = PropertyUtils.getPropertyDescriptor(myBean, conditionPropertyName);
		if (conditionDescriptor == null) {
			throw new NoSuchMethodException("Missing is"+StringUtils.capitalize(conditionPropertyName) + " method for property: " + StringUtils.uncapitalize(propertyName));
		}
		Method condition = conditionDescriptor.getReadMethod();
		if (condition == null) {
			throw new NoSuchMethodException("Missing is"+StringUtils.capitalize(conditionPropertyName) + " method for property: " + StringUtils.uncapitalize(propertyName));
		}
		if ((Boolean) condition.invoke(myBean)) {
			return method.invoke(myBean);
		}
		return null;
	}

I’ve added also a small utility static method, to make wiring the whole stuff a bit easier.

	public static <T> T create(T myBean, String suffix) {
		return (T) Enhancer.create(myBean.getClass(), new ConditionalPropertyInterceptor<T>(myBean, suffix));
	}

There’s just one last thing that needs attention – how to make sure that each getter has a corresponding isAvailable method. Yes you can take your chances and wait until application is deployed… but it’s much better to have so me kind of automatic testing – in this case I recommend using dozer library exclude transient properties and after excluding transient properties all the rest should pass.

Sources available on github