All Downloads are FREE. Search and download functionalities are using the official Maven repository.

xapi.ui.autoui.impl.UserInterfaceFactoryDefault Maven / Gradle / Ivy

The newest version!
package xapi.ui.autoui.impl;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import xapi.annotation.inject.InstanceOverride;
import xapi.log.X_Log;
import xapi.log.api.LogLevel;
import xapi.platform.GwtDevPlatform;
import xapi.platform.JrePlatform;
import xapi.ui.autoui.api.BeanValueProvider;
import xapi.ui.autoui.api.DoNotIndex;
import xapi.ui.autoui.api.UiOptions;
import xapi.ui.autoui.api.UiRendererOptions;
import xapi.ui.autoui.api.UiRenderingContext;
import xapi.ui.autoui.api.UserInterfaceFactory;
import xapi.util.X_Debug;
import xapi.util.api.ConvertsValue;

@JrePlatform
@GwtDevPlatform
@InstanceOverride(implFor=UserInterfaceFactory.class, priority=1)
public class UserInterfaceFactoryDefault extends AbstractUserInterfaceFactory{

  private static final int MAX_DEPTH = 10;
  @Override
  protected UiRenderingContext[] getOptions(final Class type) {
    final List options = new ArrayList();

    final BeanValueProvider values = getBeanProvider(type);
    // Check the package for options
    final Package pkg = type.getPackage();
    if (pkg != null && pkg.isAnnotationPresent(UiOptions.class)) {
      options.addAll(extractRenderingContext(pkg.getAnnotation(UiOptions.class), values));
    }
    if (type.isAnnotationPresent(UiOptions.class)) {
      final UiOptions opts = type.getAnnotation(UiOptions.class);
      if (opts.fields().length > 0) {
        values.setChildKeys(opts.fields());
      }
    }
    // check for enclosing types/methods?
    Class check = type;
    while (check != null) {
      // Check the type for options
      addAllRendererContexts(options, check, values);
      // Enclosing method not supported by GWT; given it adds excess complexity anyway,
      // it will not be supported in the forseeable future
//      Method enclosing = check.getEnclosingMethod();
//      if (enclosing != null){
//        addAllRendererContexts(options, enclosing, values);
//      }
      check = check.getEnclosingClass();
    }

    for (final Method m : type.getMethods()) {
      addAllRendererContexts(options, m, values);
    }
    return options.toArray(new UiRenderingContext[options.size()]);
  }

  protected void addAllRendererContexts(final List options, final AnnotatedElement element, final BeanValueProvider values) {
    if (element.isAnnotationPresent(UiOptions.class)) {
      options.addAll(extractRenderingContext(element.getAnnotation(UiOptions.class), values));
    }
    if (element.isAnnotationPresent(UiRendererOptions.class)) {
      options.addAll(extractRenderingContext(element.getAnnotation(UiRendererOptions.class), values,
          element instanceof Method ? getNameFromMethod((Method)element) : null ));
    }
  }

  @Override
  protected void recursiveAddBeanValues(final BeanValueProvider bean, final Class cls,
      final ConvertsValue converter, final String prefix, final int depth) {
    if (depth > MAX_DEPTH) {
      X_Log.warn(getClass(), "Recursion sickness detected in "+cls+" from "+prefix+"; depth reached "+MAX_DEPTH);
      if (X_Log.loggable(LogLevel.TRACE)) {
        X_Log.trace("Consider using the @DoNotIndex annotation in the recursion chain produced by "+prefix);
      }
      return;
    }
    // Add all method getter
    for (final Method m : cls.getMethods()) {
      if (
        m.getParameterTypes().length == 0
        && m.getDeclaringClass() != Object.class
        && m.getReturnType() != void.class
      ) {
        final DoNotIndex noIndex = m.getAnnotation(DoNotIndex.class);
        if (noIndex != null && noIndex.unlessDepthLessThan() >= depth) {
          continue;
        }

        final String name = getNameFromMethod(m);
        final String key = prefix.length()==0 ? name : prefix+"."+name;
        final Method rootMethod = getRootMethod(m);
        final ConvertsValue valueConverter = new ConvertsValue() {
          @Override
          public Object convert(final Object from) {
            final Object parent = converter.convert(from);
            try {
              return rootMethod.invoke(parent);
            } catch (final Exception e) {
              throw X_Debug.rethrow(e);
            }
          }
        };
        bean.addProvider(key, name, valueConverter);
        if (isNotPrimitive(m.getReturnType())) {
          recursiveAddBeanValues(bean, m.getReturnType(), valueConverter, key, depth+1);
        }
      }
    }
  }

  protected Method getRootMethod(final Method m) {
    if (m.getDeclaringClass().isInterface()) {
      // When using interfaces, search for the deepest ancestor interface with the given method.
      Method winner = m;
      for (final Class c : m.getDeclaringClass().getInterfaces()) {
        try {
          final Method method = c.getMethod(m.getName(), m.getParameterTypes());
          if (method.getDeclaringClass().isAssignableFrom(winner.getDeclaringClass())) {
            winner = method;
          }
        } catch (final Throwable ignored){}
      }
      return winner;
    }
    return m;
  }

  protected boolean isNotPrimitive(final Class cls) {
    return
        !cls.isPrimitive()
        && cls != String.class
        && (
          !cls.getPackage().getName().equals("java.lang")
            ||(
          cls != Boolean.class
          && cls != Byte.class
          && cls != Character.class
          && cls != Short.class
          && cls != Integer.class
          && cls != Long.class
          && cls != Float.class
          && cls != Double.class
        ))
    ;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy