Package com.googlecode.gwt.test.uibinder

Source Code of com.googlecode.gwt.test.uibinder.UiBinderInvocationHandler

package com.googlecode.gwt.test.uibinder;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

import com.google.gwt.dev.Link;
import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Widget;
import com.googlecode.gwt.test.exceptions.GwtTestUiBinderException;
import com.googlecode.gwt.test.exceptions.ReflectionException;
import com.googlecode.gwt.test.utils.GwtReflectionUtils;

class UiBinderInvocationHandler implements InvocationHandler {

   private static final Map<Class<?>, GwtEvent<?>> EVENT_PROTOTYPES = new HashMap<Class<?>, GwtEvent<?>>();

   private final Class<UiBinder<?, ?>> proxiedClass;

   UiBinderInvocationHandler(Class<UiBinder<?, ?>> proxiedClass) {
      this.proxiedClass = proxiedClass;
   }

   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      if (method.getName().equals("createAndBindUi")) {
         return createAndBindUi(args[0]);
      } else {
         throw new GwtTestUiBinderException("Not managed method for UiBinder : " + method.getName());
      }
   }

   @SuppressWarnings("unchecked")
   private <H extends EventHandler> void addHandlers(Object owner) {
      Map<Method, UiHandler> uiHandlerMethods = GwtReflectionUtils.getAnnotatedMethod(
               owner.getClass(), UiHandler.class);

      for (Map.Entry<Method, UiHandler> entry : uiHandlerMethods.entrySet()) {
         for (String uiFieldName : entry.getValue().value()) {
            Widget uiField = GwtReflectionUtils.getPrivateFieldValue(owner, uiFieldName);
            GwtEvent.Type<H> eventType = (GwtEvent.Type<H>) getEventType(entry.getKey());

            H handler = (H) createHandler(uiField, entry.getKey(), owner);

            if (eventType instanceof DomEvent.Type) {
               uiField.addDomHandler(handler, (DomEvent.Type<H>) eventType);
            } else {

               // special case for ValueChangeEvent and HasValueChangeHandlers

               if (uiField instanceof HasValueChangeHandlers
                        && handler instanceof ValueChangeHandler) {
                  ((HasValueChangeHandlers<Object>) uiField).addValueChangeHandler((ValueChangeHandler<Object>) handler);
               } else {
                  uiField.addHandler(handler, eventType);
               }

            }
         }

      }
   }

   /**
    * This method is in charge of the instanciation of DOM object / GWT widget and their binding
    * with @UiField in the owner
    *
    * @param owner The owner UiBinder subclass instance.
    * @return The root component, initially returned by {@link Link
    *         UiBinder#createAndBindUi(Object)}.
    */
   private Object createAndBindUi(Object owner) {
      UiBinderParser parser = new UiBinderParser();

      // parse .ui.xml file and inject @UiField
      Object rootComponent = parser.createUiComponent(proxiedClass, owner);
      // handle @UiHandlers
      addHandlers(owner);

      return rootComponent;
   }

   private InvocationHandler createEventHandlerInvocationHandler(final Method uiHandlerMethod,
            final Object uiHandlerOwner) {

      return new InvocationHandler() {

         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return GwtReflectionUtils.callPrivateMethod(uiHandlerOwner, uiHandlerMethod, args);
         }
      };
   }

   private EventHandler createHandler(Widget uiField, Method uiHandlerMethod, Object uiHandlerOwner) {
      Class<EventHandler> eventHandlerClass = findHandlerClass(uiHandlerMethod);
      InvocationHandler eventHandlerInvocationHandler = createEventHandlerInvocationHandler(
               uiHandlerMethod, uiHandlerOwner);

      return (EventHandler) Proxy.newProxyInstance(this.getClass().getClassLoader(),
               new Class<?>[]{eventHandlerClass}, eventHandlerInvocationHandler);
   }

   @SuppressWarnings("unchecked")
   private Class<EventHandler> findHandlerClass(Method uiHandlerMethod) {
      Class<?> eventTypeClass = uiHandlerMethod.getParameterTypes()[0];
      String eventHandlerClassName = eventTypeClass.getName().substring(0,
               eventTypeClass.getName().lastIndexOf("Event"))
               + "Handler";

      try {
         return (Class<EventHandler>) GwtReflectionUtils.getClass(eventHandlerClassName);
      } catch (ClassNotFoundException e) {
      }

      String anotherEventHandlerClassName = eventTypeClass.getName() + ".Handler";
      try {
         return (Class<EventHandler>) GwtReflectionUtils.getClass(anotherEventHandlerClassName);
      } catch (ClassNotFoundException e) {
         // should never happen
         throw new GwtTestUiBinderException("Cannot find handler class for event type '"
                  + eventTypeClass.getName() + "'. By convention, it should be '"
                  + eventHandlerClassName + "' or '" + anotherEventHandlerClassName + "'");
      }
   }

   private GwtEvent.Type<?> getEventType(Method method) {
      Class<?> eventTypeClass = method.getParameterTypes()[0];
      try {
         return GwtReflectionUtils.callStaticMethod(eventTypeClass, "getType");
      } catch (ReflectionException e) {
         // custom event does not respect the "TYPE" private static field
         // 'standard', we have to try to instanciate it to call
         // 'getAssociatedType()' method on it
         GwtEvent<?> eventPrototype = EVENT_PROTOTYPES.get(eventTypeClass);
         if (eventPrototype == null) {
            eventPrototype = (GwtEvent<?>) GwtReflectionUtils.instantiateClass(eventTypeClass);
            EVENT_PROTOTYPES.put(eventTypeClass, eventPrototype);
         }

         return eventPrototype.getAssociatedType();
      }

   }

}
TOP

Related Classes of com.googlecode.gwt.test.uibinder.UiBinderInvocationHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.