Package net.sourceforge.javautil.poly

Source Code of net.sourceforge.javautil.poly.PojoView

package net.sourceforge.javautil.poly;

import java.lang.annotation.Annotation;
import java.lang.reflect.Proxy;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import net.sourceforge.javautil.common.reflection.cache.ClassCache;
import net.sourceforge.javautil.common.reflection.cache.ClassField;
import net.sourceforge.javautil.interceptor.IInterceptorManager;
import net.sourceforge.javautil.interceptor.IInterceptorManipulator;
import net.sourceforge.javautil.interceptor.InterceptorUtil;
import net.sourceforge.javautil.interceptor.type.InterceptorInvocationHandler;
import net.sourceforge.javautil.interceptor.type.cjc.InterceptorProxyConstructor;
import net.sourceforge.javautil.interceptor.type.cjcw.InterceptorProxyTypeCJCW;

/**
* The central place for generating and accessing SOJO based views.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public final class PojoView {
 
  /**
   * @param instance The instance in question
   * @return True if the instance is a Super POJO (SOJO), otherwise false
   *
   * @see #isSojoType(Class)
   */
  public static boolean isSojo (Object instance) {
    return getViewMap(instance) != null;
  }
 
  /**
   * @param type The type in question
   * @return True if instances of the type can become Super POJO's (SOJO's), otherwise false
   *
   * @see #isSojo(Object)
   */
  public static boolean isSojoType (Class type) {
    return getViewDefinitions(type).size() != 0;
  }
 
  /**
   * This can be used to determine if a particular Super POJO supports a particular view.
   *
   * @param instance The instance in question.
   * @param view The view type (usually an interface)
   * @return True if the instance that was passed supports the specified view.
   */
  public static <T> boolean isSupportsView (Object instance, Class<T> view) {
    Map<Class, Object> viewMap = getViewMap(instance);
    return viewMap == null ? false : viewMap.containsKey(view);
  }
 
  /**
   * @param <T> The type of view in question
   * @param instance The instance for which a view is being requested
   * @param view The class of the view type
   * @return The view related to the instance
   * @throws IllegalArgumentException If the instance does not really support the view
   *
   * @see #isSupportsView(Object, Class)
   */
  public static <T> T getView (Object instance, Class<T> view) {
    Map<Class, Object> viewMap = getViewMap(instance);
    if (viewMap != null && viewMap.containsKey(view)) {
      Object value = viewMap.get(view);
      if (value instanceof PojoViewDefinition) {
        PojoViewDefinition definition = (PojoViewDefinition) value;
        value = createProxy(definition, instance);
        for (Class iface : definition.interfaces()) {
          viewMap.put(iface, value);
        }
      }
      return (T) value;
    }
    throw new IllegalArgumentException(instance + " does not support view: " + view);
  }
 
  /**
   * @param instance The instance for which a list of views is desired
   * @return An array, possibly empty, of views available for the instance
   */
  public static Class[] getViewsFor (Object instance) {
    Map<Class, Object> viewMap = getViewMap(instance);
    return viewMap == null ? new Class[0] : viewMap.keySet().toArray(new Class[viewMap.size()]);
  }
 
  /**
   * @param instance The instance to wrap
   * @param interceptor The interceptor related to the instance
   * @param view The view definition
   * @return The view proxy object
   */
  public static Object createView (Object instance, IInterceptorManager interceptor, PojoViewDefinition view) {
    return Proxy.newProxyInstance(instance.getClass().getClassLoader(), view.interfaces(), new PojoViewInvocationHandler(interceptor,
      instance, ClassCache.getFor(view.wrapper()).newInstance(instance)));
  }
 
  /**
   * This will use the view map extracted from the instance.
   *
   * @see #storeViewDefinitions(Class, Object, Map)
   */
  public static void storeViewDefinitions (Class type, Object instance) {
    storeViewDefinitions(type, instance, getViewMap(instance));
  }
 
  /**
   * @param type The type for which definitions will be stored
   * @param instance The instance related to the views
   * @param viewMap The view map in which to store the view information
   */
  public static void storeViewDefinitions (Class type, Object instance, Map<Class, Object> viewMap) {
    if (viewMap == null) throw new IllegalArgumentException("Must provide view map");
   
    for (PojoViewDefinition definition : getViewDefinitions(type)) {
      for (Class iface : definition.interfaces()) {
        viewMap.put(iface, definition.lazyInitialization() ? definition : createProxy(definition, instance));
      }
    }
  }
 
  /**
   * @param definition The definition from which to create a proxy
   * @param instance The instance for which this proxy is being made
   * @return A proxy for the specified instance
   */
  public static Object createProxy (PojoViewDefinition definition, Object instance) {
    return Proxy.newProxyInstance(definition.wrapper().getClassLoader(), definition.interfaces(),
      new PojoViewInvocationHandler(InterceptorUtil.getManager(instance), instance,
        ClassCache.getFor(definition.wrapper()).newInstance(instance)));
  }
 
  /**
   * @param type The type for which to retreive {@link PojoViewDefinition}'s.
   * @return The unique set of view definitions
   */
  public static Set<PojoViewDefinition> getViewDefinitions (Class type) {
    Set<PojoViewDefinition> svd = new LinkedHashSet<PojoViewDefinition>();
    findViews(type, svd);
    return svd;
  }
 
  /**
   * @param instance The instance from which to extract the view map
   * @return The view map for the instance
   *
   * @see PojoViewManipulator
   */
  protected static Map<Class, Object> getViewMap (Object instance) {
    Map<String, Object> stateMap = null;
    if (Proxy.isProxyClass(instance.getClass())) {
      InterceptorInvocationHandler svih = (InterceptorInvocationHandler) Proxy.getInvocationHandler(instance);
      stateMap = InterceptorInvocationHandler.getStateMap(svih);
     
      if (stateMap == null) return null;
    } else {
      ClassField field = ClassCache.getFor(instance.getClass()).getField(InterceptorProxyTypeCJCW.ABILITIES_FIELD_NAME);
      if (field != null && field.getFieldType() == Map.class) {
        field.getJavaMember().setAccessible(true);
        stateMap = (Map) field.getValue(instance);
      } else {
        return null;
      }
    }
   
    return (Map) stateMap.get(PojoViewManipulator.class.getName());
  }

  /**
   * Recursive loop based search for annotations that added {@link PojoViewDefinition}'s to a particular proxy class.
   *
   * @param type The type in question
   * @param abilities The unique set of abilities for the particular type
   */
  protected static void findViews (Class type, Set<PojoViewDefinition> svd) {
    for (Annotation annotation : type.getAnnotations()) {
      if (annotation.annotationType().getPackage().getName().startsWith("java")) continue;
     
      PojoViewDefinition view = annotation.annotationType().getAnnotation(PojoViewDefinition.class);
      if (view != null) svd.add(view);
      findViews(annotation.annotationType(), svd);
    }
  }
 
}
TOP

Related Classes of net.sourceforge.javautil.poly.PojoView

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.