Package com.google.gimlet.inject.annotatedwithbinder

Source Code of com.google.gimlet.inject.annotatedwithbinder.UsedToBindStuffImpl

/**
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.google.gimlet.inject.annotatedwithbinder;

import static com.google.gimlet.inject.annotatedwithbinder.AnnotatedWithBinder.TypeDef.newTypeDef;
import static com.google.gimlet.inject.annotatedwithbinder.AnnotatedWithBinder.TypeDefFlagBinder.newTypeDefFlagBinder;

import com.google.common.base.Objects;
import com.google.common.base.Throwables;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.BindingAnnotation;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.concurrent.Executors;
import java.util.logging.Logger;

import javax.annotation.Nullable;

/**
*
* @author ffaber@gmail.com (Fred Faber)
*/
public final class AnnotatedWithBinder {
  private AnnotatedWithBinder() { }

  private static final Logger logger =
      Logger.getLogger(AnnotatedWithBinder.class.getCanonicalName());

  // input => enum { DESC_1, DESC_2, ..., DESC_N }
  // plus an annotation class @UsedAsSomething

  // AnnotatedWithBinder
  //    .newAnnotatedWithBinder(binder())
  //    .bind(Thing.class)
  //    .annotatedWith(UsedAsSomething.class, DESC_1)
  //    ...;
  //

  // what we want to do is to be sure we can take an annotation and then
  // dynamically create the instance thereof.

  // so given an annotation


  @Retention(RetentionPolicy.RUNTIME)
  @Target(ElementType.PARAMETER)
  @BindingAnnotation
  @interface UsedToBindStuff {
    Point value();

    enum Point { P1, P2 }

    @SuppressWarnings("ClassExplicitlyAnnotation")
    class UsedToBindStuffImpl implements UsedToBindStuff {

      @Override public Point value() {
        return null;
      }

      @Override public Class<? extends Annotation> annotationType() {
        return null;
      }
    }

    UsedToBindStuff usedToBindStuff = new UsedToBindStuffImpl();
  }

  public void doNothing(@UsedToBindStuff(UsedToBindStuff.Point.P1) Object point1) {
    UsedToBindStuff usedToBindStuff2 = UsedToBindStuff.usedToBindStuff;
  }

  interface TypeDef2<T> {
  }


    static class TypeDef<T> /* extends ValueType */ {
      // TODO(ffaber): if we have a SettableTypeDef, that means we should be
      // able to assign this field through the binder.
      // static class BigtableName extends SettableTypeDef<T> { }

      @Nullable private final T value;

      protected TypeDef() { this(null); }

      protected TypeDef(T value) {
        this.value = value;
      }

      static <T, D extends TypeDef<T>> D newTypeDef(
          Class<D> typeDefClass, T value)
          throws IllegalAccessException, InstantiationException,
          NoSuchFieldException {
        System.err.println("callspot: " + Throwables.getStackTraceAsString(new Exception()));
        D typeDef;
        try {
          Constructor<? extends TypeDef<?>> constructor =
              typeDefClass.getDeclaredConstructor(value.getClass());
          constructor.setAccessible(true);
          typeDef = (D) constructor.newInstance(value);
        } catch (Exception e) {
          typeDef = typeDefClass.newInstance();
          Field valueField =
              typeDefClass.getSuperclass().getDeclaredField("value");
          valueField.setAccessible(true);
          valueField.set(typeDef, value);
        }
        return typeDef;
      }

      public T value() {
        return value;
      }
     
      @Override public final String toString() {
        return Objects.toStringHelper(getClass())
            .add("value", value)
            .toString();
      }

      @Override public final int hashCode() {
        return Objects.hashCode(value);
      }

      @Override public final boolean equals(Object other) {
        if (this == other) {
          return true;
        }

        if (other == null || !(other.getClass() == this.getClass())) {
          return false;
        }

        return Objects.equal(
            this.value, ((TypeDef) other).value);
      }
    }

  static final class BigtableName extends TypeDef<String> {
    BigtableName(String underlyingValue) {
      super(underlyingValue);
    }
  }

  static final class NumberOfOssThreads extends TypeDef<Integer> {
    NumberOfOssThreads(Integer underlyingValue) {
      super(underlyingValue);
    }
  }

  static final class NumberOfOssThreads2 extends TypeDef<Integer> { }
 
  void instantiateTypeDefManually() {
  }

  // Flag binder replacement.
  // @SomeRealAnnotation
  // private final static Flag<Type> someFlag = ...;

  // @SomeRealAnnotation(GIVES_THREAD_COUNT)
  // private final static Flag<Type> someFlag = ...;

  // @BindAsTypeDef(TypeDefClass.class)
  // private final static Flag<Type> someFlag = ...;

  // TypeDefFlagBinder.bindTypeDefFlags(getClass());

  static class Flag<T> {

    static <T> Flag<T> value(T defaultValue) {
      return new Flag<T>(defaultValue);
    }

    private final T defaultValue;

    Flag(T defaultValue) {
      this.defaultValue = defaultValue ;
    }

    public T getValue() {
      return defaultValue; // for now
    }
  }

  private static final Flag<Integer> numberOfOssThreads = Flag.value(100);
  private static final Flag<String> bigtableName =
      Flag.value("/bigtable/mix-gd/some-table");

  @Retention(RetentionPolicy.RUNTIME)
  @Target(ElementType.FIELD)
  @interface BindAsTypeDef {
    Class<? extends TypeDef<?>> value();
  }
 
  static class TypeDefFlagBinder {
    static TypeDefFlagBinder newTypeDefFlagBinder(Binder binder) {
      return new TypeDefFlagBinder(binder);
    }

    private final Binder binder;

    private TypeDefFlagBinder(Binder binder) {
      this.binder = binder.skipSources(getClass());
    }

    void bindTypeDefFlags(Class<?> clazz) {
      try {
        innerBindTypeDefFlags(clazz);
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }

    void innerBindTypeDefFlags(Class<?> clazz)
        throws IllegalAccessException, NoSuchMethodException,
        InvocationTargetException, InstantiationException,
        NoSuchFieldException {
      Field[] fields = clazz.getDeclaredFields();
      for (Field field : fields) {
        BindAsTypeDef bindAsTypeDef = field.getAnnotation(BindAsTypeDef.class);
        if (bindAsTypeDef == null) {
          continue;
        }
       
        int modifierMask = field.getModifiers();
       
        boolean isFinal = (Modifier.FINAL & modifierMask) > 0;
        if (!isFinal) {
          System.err.println("Your flags should be final");
        }
       
        boolean isPrivate = (Modifier.PRIVATE & modifierMask) > 0;
        if (!isPrivate) {
          System.err.println("Your flags should be private");
        }

        field.setAccessible(true);
        Object flagField = field.get(null);
        if (!(flagField instanceof Flag)) {
          System.err.println("Wrongly annotated field: " + flagField);
          continue;
        }

        Flag<?> flag = (Flag) flagField;
        Object flagValue = flag.getValue();
        Class<? extends TypeDef<?>> typeDefClass = bindAsTypeDef.value();
        // TODO(ffaber): if the typedef is of type 'SettableTypeDef' and doesn't
        // have a ctr to use, then just set the field directly.

        TypeDef<?> typeDef = (TypeDef<?>) newTypeDef((Class) typeDefClass, flagValue);

        System.err.println("typedef is: " + typeDef);
        System.err.println("typedefClass is: " + typeDefClass);
        System.err.println("typedefClass x 2 is: " + typeDef.getClass());
        // Then we need to get an instance of the subclass from this shit.
        bindTypeDef(typeDefClass, typeDef);
      }
    }

    void useCglib(final TypeDef<?> typeDef, Class<? extends TypeDef<?>> typeDefClass) {
      Enhancer enhancer = new Enhancer();
      enhancer.setSuperclass(typeDefClass);
      enhancer.setCallback(new MethodInterceptor() {
        @Override public Object intercept(
            Object obj, Method method, Object[] args, MethodProxy proxy)
            throws Throwable {
          return method.invoke(typeDef, args);
        }
      });
      TypeDef<?> enhancedTypeDef = (TypeDef<?>) enhancer.create();
      System.err.println("typedefClass x 3 is: " + enhancedTypeDef.getClass());
    }

    @SuppressWarnings("unchecked")
    void bindTypeDef(
        Class<? extends TypeDef<?>> typeDefClass, TypeDef<?> typeDef) {
      binder.bind((Class) typeDefClass).toInstance(typeDef);
    }
  }

  private static TypeDef<?> newTypeDef1(
      Object flagValue,
      Class<? extends TypeDef<?>> typeDefClass)
      throws InstantiationException, IllegalAccessException,
      NoSuchFieldException {
    TypeDef<?> typeDef;
    try {
      Constructor<? extends TypeDef<?>> constructor =
          typeDefClass.getDeclaredConstructor(flagValue.getClass());
      constructor.setAccessible(true);
      typeDef = constructor.newInstance(flagValue);
    } catch (Exception e) {
      System.err.println("exception below:");
      e.printStackTrace();
//          Constructor<?> constructor =
//              typeDefClass.getSuperclass().getDeclaredConstructor();
//          constructor.setAccessible(true);
//          typeDef = (TypeDef<?>) constructor.newInstance();

      typeDef = typeDefClass.newInstance();
      Field valueField =
          typeDefClass.getSuperclass().getDeclaredField("value");
      valueField.setAccessible(true);
      valueField.set(typeDef, flagValue);
    }
    return typeDef;
  }

  static class TypeDefUsingModule extends AbstractModule {
    @BindAsTypeDef(NumberOfOssThreads2.class)
    private static final Flag<Integer> numberOfOssThreads2 = Flag.value(100);

    @BindAsTypeDef(BigtableName.class)
    private static final Flag<String> bigtableName2 =
        Flag.value("/bigtable/mix-gd/some-table");

    @Override protected void configure() {
      newTypeDefFlagBinder(binder()).bindTypeDefFlags(getClass());
    }
  }

  public static void main(String[] args) throws Exception {
    NumberOfOssThreads2 numberOfOssThreads2 = new NumberOfOssThreads2();
    System.err.println("numberOfOssThreads2: " + numberOfOssThreads2);

    Injector injector = Guice.createInjector(new TypeDefUsingModule());
    GetsInjectedWithStuff getsInjectedWithStuff =
        injector.getInstance(GetsInjectedWithStuff.class);
    getsInjectedWithStuff.doFakeStuff();
   
    NumberOfOssThreads2 manuallyCreatedNumberOfOssThreads2 =
        NumberOfOssThreads2.newTypeDef(NumberOfOssThreads2.class, 3);
    BigtableName manuallyCreatedBigtableName =
        newTypeDef(BigtableName.class, "bigbigtable");
    GetsInjectedWithStuff manuallyCreatedGetsInjectedWithStuff =
        new GetsInjectedWithStuff(
            manuallyCreatedNumberOfOssThreads2,
            manuallyCreatedBigtableName);
    manuallyCreatedGetsInjectedWithStuff.doFakeStuff();
  }


  static class GetsInjectedWithStuff {
    private final NumberOfOssThreads2 numberOfOssThreads;
    private final BigtableName bigtableName;

    @Inject GetsInjectedWithStuff(
        NumberOfOssThreads2 numberOfOssThreads,
        BigtableName bigtableName) {
      this.numberOfOssThreads = numberOfOssThreads;
      this.bigtableName = bigtableName;
    }

    public void doFakeStuff() {
      System.err.println("Bigtable name: " + bigtableName);
      System.err.println("Bigtable name: " + bigtableName.value());
      System.err.println("Number of threads: " + numberOfOssThreads);
      System.err.println("Number of threads: " + numberOfOssThreads.value());
    }

    public void doStuff() {
      fakeOpenBigtable(bigtableName.value());
      Executors.newFixedThreadPool(numberOfOssThreads.value());
    }

    public void fakeOpenBigtable(String bigtableName) {
    }
  }

}
TOP

Related Classes of com.google.gimlet.inject.annotatedwithbinder.UsedToBindStuffImpl

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.