package com.googlecode.gwt.test.internal.handlers; import com.google.gwt.place.impl.AbstractPlaceHistoryMapper; import com.google.gwt.place.shared.Place; import com.google.gwt.place.shared.PlaceHistoryMapper; import com.google.gwt.place.shared.PlaceTokenizer; import com.google.gwt.place.shared.WithTokenizers; import com.googlecode.gwt.test.GwtCreateHandler; import com.googlecode.gwt.test.exceptions.GwtTestPatchException; import com.googlecode.gwt.test.utils.GwtReflectionUtils; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; class PlaceHistoryMapperCreateHandler implements GwtCreateHandler { private static final class GwtTestPlaceHistoryMapper extends AbstractPlaceHistoryMapper<Object> { private final Map<Class<?>, String> prefixMap; private final Map<String, PlaceTokenizer<?>> tokenizerMap; private GwtTestPlaceHistoryMapper(Class<? extends PlaceTokenizer<?>>[] placeTokenizers) { this.prefixMap = new HashMap<Class<?>, String>(); this.tokenizerMap = new HashMap<String, PlaceTokenizer<?>>(); collectTokenizerByPrefix(placeTokenizers); } @Override protected PrefixAndToken getPrefixAndToken(Place newPlace) { String prefix = prefixMap.get(newPlace.getClass()); PlaceTokenizer<?> tokenizer = getTokenizer(prefix); if (tokenizer == null) { return null; } String token = GwtReflectionUtils.callPrivateMethod(tokenizer, "getToken", newPlace); return new PrefixAndToken(prefix, token); } @Override protected PlaceTokenizer<?> getTokenizer(String prefix) { return tokenizerMap.get(prefix); } private void collectTokenizerByPrefix(Class<? extends PlaceTokenizer<?>>[] placeTokenizers) { for (Class<? extends PlaceTokenizer<?>> tokenizerClass : placeTokenizers) { try { Method getPlaceMethod = tokenizerClass.getMethod("getPlace", String.class); Class<?> placeClass = getPlaceMethod.getReturnType(); String placePrefix = createUniquePrefix(placeClass); PlaceTokenizer<?> instance = GwtReflectionUtils.instantiateClass(tokenizerClass); tokenizerMap.put(placePrefix, instance); prefixMap.put(placeClass, placePrefix); } catch (Exception e) { // should never happened : just mute this throw e.printStackTrace(); } } } private String createUniquePrefix(Class<?> placeClass) { String prefix = placeClass.getSimpleName(); String uniquePrefix = prefix; int i = 1; while (tokenizerMap.containsKey(uniquePrefix)) { uniquePrefix = prefix + i; i++; } return uniquePrefix; } } private static final class PlaceHistoryInvocationHandler implements InvocationHandler { private final GwtTestPlaceHistoryMapper placeHistoryMapper; private PlaceHistoryInvocationHandler(Class<? extends PlaceTokenizer<?>>[] placeTokenizers) { placeHistoryMapper = new GwtTestPlaceHistoryMapper(placeTokenizers); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("getPlace")) { return placeHistoryMapper.getPlace((String) args[0]); } else if (method.getName().equals("getToken")) { return placeHistoryMapper.getToken((Place) args[0]); } else { throw new GwtTestPatchException( "Unhandled method '" + method.getDeclaringClass().getName() + "." + method.getName() + "' by the default gwt-test-utils GwtCreateHandler for PlaceHistoryMapper subtypes"); } } } public Object create(Class<?> classLiteral) throws Exception { if (!PlaceHistoryMapper.class.isAssignableFrom(classLiteral)) { return null; } WithTokenizers withTokenizers = classLiteral.getAnnotation(WithTokenizers.class); if (withTokenizers == null) { throw new GwtTestPatchException( "Error while trying to create an instance of " + classLiteral.getName() + " : gwt-test-utils default GwtCreateHandler for PlaceHistoryMapper is not currently able to create a valid implementation without relying on the @WithTokenizer annotation"); } return Proxy.newProxyInstance(classLiteral.getClassLoader(), new Class<?>[]{classLiteral}, new PlaceHistoryInvocationHandler(withTokenizers.value())); } }