/*
 * Copyright (C) 2008 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.inject.spi;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.base.Objects;
import com.google.inject.Binder;
import com.google.inject.ConfigurationException;
import com.google.inject.TypeLiteral;
import java.util.Set;

/**
 * A request to inject the instance fields and methods of an instance. Requests are created
 * explicitly in a module using {@link com.google.inject.Binder#requestInjection(Object)
 * requestInjection()} statements:
 *
 *

 *     requestInjection(serviceInstance);

 *
 * @author mikeward@google.com (Mike Ward)
 * @since 2.0
 */
public final class InjectionRequest<T> implements Element {

  private final Object source;
  private final TypeLiteral<T> type;
  private final T instance;

  public InjectionRequest(Object source, TypeLiteral<T> type, T instance) {
    this.source = checkNotNull(source, "source");
    this.type = checkNotNull(type, "type");
    this.instance = instance;
  }

  @Override
  public Object getSource() {
    return source;
  }

  /**
   * Returns the instance that injection is being requested on. This may be null for injection
   * requests returned from an Injector, to allow the injector to reclaim memory.
   */
  public T getInstance() {
    return instance;
  }

  public TypeLiteral<T> getType() {
    return type;
  }

  /**
   * Returns the instance methods and fields of {@code instance} that will be injected to fulfill
   * this request.
   *
   * @return a possibly empty set of injection points. The set has a specified iteration order. All
   *     fields are returned and then all methods. Within the fields, supertype fields are returned
   *     before subtype fields. Similarly, supertype methods are returned before subtype methods.
   * @throws ConfigurationException if there is a malformed injection point on the class of {@code
   *     instance}, such as a field with multiple binding annotations. The exception's {@link
   *     ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} of
   *     the valid injection points.
   */
  public Set<InjectionPoint> getInjectionPoints() throws ConfigurationException {
    return InjectionPoint.forInstanceMethodsAndFields(
        instance != null ? TypeLiteral.get(instance.getClass()) : type);
  }

  @Override
  public <R> R acceptVisitor(ElementVisitor<R> visitor) {
    return visitor.visit(this);
  }

  @Override
  public void applyTo(Binder binder) {
    binder.withSource(getSource()).requestInjection(type, instance);
  }

  @Override
  public boolean equals(Object obj) {
    return obj instanceof InjectionRequest
        && Objects.equal(((InjectionRequest<?>) obj).instance, instance)
        && ((InjectionRequest<?>) obj).type.equals(type)
        && ((InjectionRequest<?>) obj).source.equals(source);
  }

  @Override
  public int hashCode() {
    return Objects.hashCode(type, source);
  }
}


/*
 * Copyright (C) 2013 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.inject.internal;

import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.logging.Logger;
/**
 * Contains flags for Guice.
 */
public class InternalFlags {
  private static final Logger logger = Logger.getLogger(InternalFlags.class.getName());

  private static final IncludeStackTraceOption INCLUDE_STACK_TRACES
      = parseIncludeStackTraceOption();

  private static final CustomClassLoadingOption CUSTOM_CLASS_LOADING
      = parseCustomClassLoadingOption();

  private static final NullableProvidesOption NULLABLE_PROVIDES
      = parseNullableProvidesOption(NullableProvidesOption.ERROR);

  /**
   * The options for Guice stack trace collection.
   */
  public enum IncludeStackTraceOption {
    /** No stack trace collection */
    OFF,
    /**  Minimum stack trace collection (Default) */
    ONLY_FOR_DECLARING_SOURCE,
    /** Full stack trace for everything */
    COMPLETE
  }

  /**
   * The options for Guice custom class loading.
   */
  public enum CustomClassLoadingOption {
    /** No custom class loading */
    OFF,
    /** Automatically bridge between class loaders (Default) */
    BRIDGE
  }

  public enum NullableProvidesOption {
    /** Ignore null parameters to @Provides methods. */
    IGNORE,
    /** Warn if null parameters are passed to non-@Nullable parameters of provides methods. */
    WARN,
    /** Error if null parameters are passed to non-@Nullable parameters of provides parameters */
    ERROR
  }

  public static IncludeStackTraceOption getIncludeStackTraceOption() {
    return INCLUDE_STACK_TRACES;
  }

  public static CustomClassLoadingOption getCustomClassLoadingOption() {
    return CUSTOM_CLASS_LOADING;
  }

  public static NullableProvidesOption getNullableProvidesOption() {
    return NULLABLE_PROVIDES;
  }

  private static IncludeStackTraceOption parseIncludeStackTraceOption() {
    return getSystemOption("guice_include_stack_traces",
        IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE);
  }

  private static CustomClassLoadingOption parseCustomClassLoadingOption() {
    return getSystemOption("guice_custom_class_loading",
        CustomClassLoadingOption.BRIDGE, CustomClassLoadingOption.OFF);
  }

  private static NullableProvidesOption parseNullableProvidesOption(
      NullableProvidesOption defaultValue) {
    return getSystemOption("guice_check_nullable_provides_params", defaultValue);
  }

  /**
   * Gets the system option indicated by the specified key; runs as a privileged action.
   *
   * @param name of the system option
   * @param defaultValue if the option is not set
   *
   * @return value of the option, defaultValue if not set
   */
  private static <T extends Enum<T>> T getSystemOption(final String name, T defaultValue) {
    return getSystemOption(name, defaultValue, defaultValue);
  }

  /**
   * Gets the system option indicated by the specified key; runs as a privileged action.
   *
   * @param name of the system option
   * @param defaultValue if the option is not set
   * @param secureValue if the security manager disallows access to the option
   *
   * @return value of the option, defaultValue if not set, secureValue if no access
   */
  private static <T extends Enum<T>> T getSystemOption(final String name, T defaultValue,
      T secureValue) {
    Class<T> enumType = defaultValue.getDeclaringClass();
    String value = null;
    try {
      value =
          AccessController.doPrivileged(
              new PrivilegedAction<String>() {
                @Override
                public String run() {
                  return System.getProperty(name);
                }
              });
      return (value != null && value.length() > 0) ? Enum.valueOf(enumType, value) : defaultValue;
    } catch (SecurityException e) {
      return secureValue;
    } catch (IllegalArgumentException e) {
      logger.warning(value + " is not a valid flag value for " + name + ". "
          + " Values must be one of " + Arrays.asList(enumType.getEnumConstants()));
      return defaultValue;
    }
  }
}


/*
 * Copyright (C) 2008 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.inject.grapher;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import com.google.inject.internal.ProviderMethod;
import com.google.inject.internal.util.StackTraceElements;
import com.google.inject.spi.ElementSource;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.List;

/**
 * Reasonable implementation for {@link NameFactory}. Mostly takes various {@link
 * Object#toString()}s and strips package names out of them so that they'll fit on the graph.
 *
 * @author phopkins@gmail.com (Pete Hopkins)
 */
public class ShortNameFactory implements NameFactory {
  @Override
  public String getMemberName(Member member) {
    if (member instanceof Constructor) {
      return "<init>";
    } else if (member instanceof Method) {
      return "#" + member.getName() + "(...)";
    } else {
      return member.getName();
    }
  }

  @Override
  public String getAnnotationName(Key<?> key) {
    Annotation annotation = key.getAnnotation();
    Class<? extends Annotation> annotationType = key.getAnnotationType();
    if (annotation != null) {
      annotationType = annotation.annotationType();

      String annotationString = annotation.toString();
      String canonicalName = annotationType.getName();
      String simpleName = annotationType.getSimpleName();

      return annotationString.replace(canonicalName, simpleName).replace("()", "");
    } else if (annotationType != null) {
      return "@" + annotationType.getSimpleName();
    } else {
      return "";
    }
  }

  @Override
  public String getClassName(Key<?> key) {
    TypeLiteral<?> typeLiteral = key.getTypeLiteral();
    return stripPackages(typeLiteral.toString());
  }

  @Override
  public String getInstanceName(Object instance) {
    if (instance instanceof ProviderMethod) {
      return getMethodString(((ProviderMethod<?>) instance).getMethod());
    }

    if (instance instanceof CharSequence) {
      return "\"" + instance + "\"";
    }

    try {
      if (instance.getClass().getMethod("toString").getDeclaringClass().equals(Object.class)) {
        return stripPackages(instance.getClass().getName());
      }
    } catch (SecurityException e) {
      throw new AssertionError(e);
    } catch (NoSuchMethodException e) {
      throw new AssertionError(e);
    }

    return instance.toString();
  }

  /**
   * Returns a name for a Guice "source" object. This will typically be either a {@link
   * StackTraceElement} for when the binding is made to the instance, or a {@link Method} when a
   * provider method is used.
   */
  @Override
  public String getSourceName(Object source) {
    if (source instanceof ElementSource) {
      source = ((ElementSource) source).getDeclaringSource();
    }
    if (source instanceof Method) {
      source = StackTraceElements.forMember((Method) source);
    }

    if (source instanceof StackTraceElement) {
      return getFileString((StackTraceElement) source);
    }

    return stripPackages(source.toString());
  }

  protected String getFileString(StackTraceElement stackTraceElement) {
    return stackTraceElement.getFileName() + ":" + stackTraceElement.getLineNumber();
  }

  protected String getMethodString(Method method) {
    List<String> paramStrings = Lists.newArrayList();
    for (Class<?> paramType : method.getParameterTypes()) {
      paramStrings.add(paramType.getSimpleName());
    }

    String paramString = Joiner.on(", ").join(paramStrings);
    return "#" + method.getName() + "(" + paramString + ")";
  }

  /**
   * Eliminates runs of lowercase characters and numbers separated by periods. Seems to remove
   * packages from fully-qualified type names pretty well.
   */
  private String stripPackages(String str) {
    return str.replaceAll("(^|[< .\\(])([a-z0-9]+\\.)*", "$1");
  }
}


/*
 * Copyright (C) 2008 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.inject.util;

import com.google.inject.Provider;
import com.google.inject.internal.MoreTypes;
import com.google.inject.internal.MoreTypes.GenericArrayTypeImpl;
import com.google.inject.internal.MoreTypes.ParameterizedTypeImpl;
import com.google.inject.internal.MoreTypes.WildcardTypeImpl;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Static methods for working with types.
 *
 * @author crazybob@google.com (Bob Lee)
 * @since 2.0
 */
public final class Types {
  private Types() {}

  /**
   * Returns a new parameterized type, applying {@code typeArguments} to {@code rawType}. The
   * returned type does not have an owner type.
   *
   * @return a {@link java.io.Serializable serializable} parameterized type.
   */
  public static ParameterizedType newParameterizedType(Type rawType, Type... typeArguments) {
    return newParameterizedTypeWithOwner(null, rawType, typeArguments);
  }

  /**
   * Returns a new parameterized type, applying {@code typeArguments} to {@code rawType} and
   * enclosed by {@code ownerType}.
   *
   * @return a {@link java.io.Serializable serializable} parameterized type.
   */
  public static ParameterizedType newParameterizedTypeWithOwner(
      Type ownerType, Type rawType, Type... typeArguments) {
    return new ParameterizedTypeImpl(ownerType, rawType, typeArguments);
  }

  /**
   * Returns an array type whose elements are all instances of {@code componentType}.
   *
   * @return a {@link java.io.Serializable serializable} generic array type.
   */
  public static GenericArrayType arrayOf(Type componentType) {
    return new GenericArrayTypeImpl(componentType);
  }

  /**
   * Returns a type that represents an unknown type that extends {@code bound}. For example, if
   * {@code bound} is {@code CharSequence.class}, this returns {@code ? extends CharSequence}. If
   * {@code bound} is {@code Object.class}, this returns {@code ?}, which is shorthand for {@code ?
   * extends Object}.
   */
  public static WildcardType subtypeOf(Type bound) {
    return new WildcardTypeImpl(new Type[] {bound}, MoreTypes.EMPTY_TYPE_ARRAY);
  }

  /**
   * Returns a type that represents an unknown supertype of {@code bound}. For example, if {@code
   * bound} is {@code String.class}, this returns {@code ? super String}.
   */
  public static WildcardType supertypeOf(Type bound) {
    return new WildcardTypeImpl(new Type[] {Object.class}, new Type[] {bound});
  }

  /**
   * Returns a type modelling a {@link List} whose elements are of type {@code elementType}.
   *
   * @return a {@link java.io.Serializable serializable} parameterized type.
   */
  public static ParameterizedType listOf(Type elementType) {
    return newParameterizedType(List.class, elementType);
  }

  /**
   * Returns a type modelling a {@link Collection} whose elements are of type {@code elementType}.
   *
   * @return a {@link java.io.Serializable serializable} parameterized type.
   */
  public static ParameterizedType collectionOf(Type elementType) {
    return newParameterizedType(Collection.class, elementType);
  }

  /**
   * Returns a type modelling a {@link Set} whose elements are of type {@code elementType}.
   *
   * @return a {@link java.io.Serializable serializable} parameterized type.
   */
  public static ParameterizedType setOf(Type elementType) {
    return newParameterizedType(Set.class, elementType);
  }

  /**
   * Returns a type modelling a {@link Map} whose keys are of type {@code keyType} and whose values
   * are of type {@code valueType}.
   *
   * @return a {@link java.io.Serializable serializable} parameterized type.
   */
  public static ParameterizedType mapOf(Type keyType, Type valueType) {
    return newParameterizedType(Map.class, keyType, valueType);
  }

  // for other custom collections types, use newParameterizedType()

  /**
   * Returns a type modelling a {@link Provider} that provides elements of type {@code elementType}.
   *
   * @return a {@link java.io.Serializable serializable} parameterized type.
   */
  public static ParameterizedType providerOf(Type providedType) {
    return newParameterizedType(Provider.class, providedType);
  }

  /**
   * Returns a type modelling a {@link javax.inject.Provider} that provides elements of type {@code
   * elementType}.
   *
   * @return a {@link java.io.Serializable serializable} parameterized type.
   */
  public static Type javaxProviderOf(Type type) {
    return Types.newParameterizedType(javax.inject.Provider.class, type);
  }
}


/*
 * Copyright (C) 2008 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.inject.internal;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.inject.Binder;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.Message;
import com.google.inject.spi.ModuleAnnotatedMethodScanner;
import com.google.inject.util.Modules;
import java.lang.annotation.Annotation;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;

/**
 * Creates bindings to methods annotated with {@literal @}{@link Provides}. Use the scope and
 * binding annotations on the provider method to configure the binding.
 *
 * @author crazybob@google.com (Bob Lee)
 * @author jessewilson@google.com (Jesse Wilson)
 */
public final class ProviderMethodsModule implements Module {
  private final Object delegate;
  private final TypeLiteral<?> typeLiteral;
  private final boolean skipFastClassGeneration;
  private final ModuleAnnotatedMethodScanner scanner;

  private ProviderMethodsModule(
      Object delegate, boolean skipFastClassGeneration, ModuleAnnotatedMethodScanner scanner) {
    this.delegate = checkNotNull(delegate, "delegate");
    this.typeLiteral = TypeLiteral.get(this.delegate.getClass());
    this.skipFastClassGeneration = skipFastClassGeneration;
    this.scanner = scanner;
  }

  /** Returns a module which creates bindings for provider methods from the given module. */
  public static Module forModule(Module module) {
    return forObject(module, false, ProvidesMethodScanner.INSTANCE);
  }

  /** Returns a module which creates bindings methods in the module that match the scanner. */
  public static Module forModule(Object module, ModuleAnnotatedMethodScanner scanner) {
    return forObject(module, false, scanner);
  }

  /**
   * Returns a module which creates bindings for provider methods from the given object. This is
   * useful notably for GIN
   *
   *
This will skip bytecode generation for provider methods, since it is assumed that callers
   * are only interested in Module metadata.
   */
  public static Module forObject(Object object) {
    return forObject(object, true, ProvidesMethodScanner.INSTANCE);
  }

  private static Module forObject(
      Object object, boolean skipFastClassGeneration, ModuleAnnotatedMethodScanner scanner) {
    // avoid infinite recursion, since installing a module always installs itself
    if (object instanceof ProviderMethodsModule) {
      return Modules.EMPTY_MODULE;
    }

    return new ProviderMethodsModule(object, skipFastClassGeneration, scanner);
  }

  public Object getDelegateModule() {
    return delegate;
  }

  @Override
  public void configure(Binder binder) {
    for (ProviderMethod<?> providerMethod : getProviderMethods(binder)) {
      providerMethod.configure(binder);
    }
  }

  public List<ProviderMethod<?>> getProviderMethods(Binder binder) {
    List<ProviderMethod<?>> result = null;
    // The highest class in the type hierarchy that contained a provider method definition.
    Class<?> superMostClass = delegate.getClass();
    for (Class<?> c = delegate.getClass(); c != Object.class; c = c.getSuperclass()) {
      for (Method method : DeclaredMembers.getDeclaredMethods(c)) {
        Annotation annotation = getAnnotation(binder, method);
        if (annotation != null) {
          if (result == null) {
            result = Lists.newArrayList();
          }
          result.add(createProviderMethod(binder, method, annotation));
          superMostClass = c;
        }
      }
    }
    if (result == null) {
      // We didn't find anything
      return ImmutableList.of();
    }
    // We have found some provider methods, now we need to check if any were overridden.
    // We do this as a separate pass to avoid calculating all the signatures when there are no
    // provides methods, or when all provides methods are defined in a single class.
    Multimap<Signature, Method> methodsBySignature = null;
    // We can stop scanning when we see superMostClass, since no superclass method can override
    // a method in a subclass.  Corrollary, if superMostClass == delegate.getClass(), there can be
    // no overrides of a provides method.
    for (Class<?> c = delegate.getClass(); c != superMostClass; c = c.getSuperclass()) {
      for (Method method : c.getDeclaredMethods()) {
        if (((method.getModifiers() & (Modifier.PRIVATE | Modifier.STATIC)) == 0)
            && !method.isBridge()
            && !method.isSynthetic()) {
          if (methodsBySignature == null) {
            methodsBySignature = HashMultimap.create();
          }
          methodsBySignature.put(new Signature(typeLiteral, method), method);
        }
      }
    }
    if (methodsBySignature != null) {
      // we have found all the signatures and now need to identify if any were overridden
      // In the worst case this will have O(n^2) in the number of @Provides methods, but that is
      // only assuming that every method is an override, in general it should be very quick.
      for (ProviderMethod<?> provider : result) {
        Method method = provider.getMethod();
        for (Method matchingSignature :
            methodsBySignature.get(new Signature(typeLiteral, method))) {
          // matching signature is in the same class or a super class, therefore method cannot be
          // overridding it.
          if (matchingSignature.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) {
            continue;
          }
          // now we know matching signature is in a subtype of method.getDeclaringClass()
          if (overrides(matchingSignature, method)) {
            String annotationString =
                provider.getAnnotation().annotationType() == Provides.class
                    ? "@Provides"
                    : "@" + provider.getAnnotation().annotationType().getCanonicalName();
            binder.addError(
                "Overriding "
                    + annotationString
                    + " methods is not allowed."
                    + "\n\t"
                    + annotationString
                    + " method: %s\n\toverridden by: %s",
                method,
                matchingSignature);
            break;
          }
        }
      }
    }
    return result;
  }

  /** Returns the annotation that is claimed by the scanner, or null if there is none. */
  private Annotation getAnnotation(Binder binder, Method method) {
    if (method.isBridge() || method.isSynthetic()) {
      return null;
    }
    Annotation annotation = null;
    for (Class<? extends Annotation> annotationClass : scanner.annotationClasses()) {
      Annotation foundAnnotation = method.getAnnotation(annotationClass);
      if (foundAnnotation != null) {
        if (annotation != null) {
          binder.addError(
              "More than one annotation claimed by %s on method %s."
                  + " Methods can only have one annotation claimed per scanner.",
              scanner, method);
          return null;
        }
        annotation = foundAnnotation;
      }
    }
    return annotation;
  }

  private static final class Signature {
    final Class<?>[] parameters;
    final String name;
    final int hashCode;

    Signature(TypeLiteral<?> typeLiteral, Method method) {
      this.name = method.getName();
      // We need to 'resolve' the parameters against the actual class type in case this method uses
      // type parameters.  This is so we can detect overrides of generic superclass methods where
      // the subclass specifies the type parameter.  javac implements these kinds of overrides via
      // bridge methods, but we don't want to give errors on bridge methods (but rather the target
      // of the bridge).
      List<TypeLiteral<?>> resolvedParameterTypes = typeLiteral.getParameterTypes(method);
      this.parameters = new Class<?>[resolvedParameterTypes.size()];
      int i = 0;
      for (TypeLiteral<?> type : resolvedParameterTypes) {
        parameters[i] = type.getRawType();
      }
      this.hashCode = name.hashCode() + 31 * Arrays.hashCode(parameters);
    }

    @Override
    public boolean equals(Object obj) {
      if (obj instanceof Signature) {
        Signature other = (Signature) obj;
        return other.name.equals(name) && Arrays.equals(parameters, other.parameters);
      }
      return false;
    }

    @Override
    public int hashCode() {
      return hashCode;
    }
  }

  /** Returns true if a overrides b, assumes that the signatures match */
  private static boolean overrides(Method a, Method b) {
    // See JLS section 8.4.8.1
    int modifiers = b.getModifiers();
    if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) {
      return true;
    }
    if (Modifier.isPrivate(modifiers)) {
      return false;
    }
    // b must be package-private
    return a.getDeclaringClass().getPackage().equals(b.getDeclaringClass().getPackage());
  }

  private <T> ProviderMethod<T> createProviderMethod(
      Binder binder, Method method, Annotation annotation) {
    binder = binder.withSource(method);
    Errors errors = new Errors(method);

    // prepare the parameter providers
    InjectionPoint point = InjectionPoint.forMethod(method, typeLiteral);
    @SuppressWarnings("unchecked") // Define T as the method's return type.
    TypeLiteral<T> returnType = (TypeLiteral<T>) typeLiteral.getReturnType(method);
    Key<T> key = getKey(errors, returnType, method, method.getAnnotations());
    try {
      key = scanner.prepareMethod(binder, annotation, key, point);
    } catch (Throwable t) {
      binder.addError(t);
    }
    Class<? extends Annotation> scopeAnnotation =
        Annotations.findScopeAnnotation(errors, method.getAnnotations());
    for (Message message : errors.getMessages()) {
      binder.addError(message);
    }
    return ProviderMethod.create(
        key,
        method,
        delegate,
        ImmutableSet.copyOf(point.getDependencies()),
        scopeAnnotation,
        skipFastClassGeneration,
        annotation);
  }

  <T> Key<T> getKey(Errors errors, TypeLiteral<T> type, Member member, Annotation[] annotations) {
    Annotation bindingAnnotation = Annotations.findBindingAnnotation(errors, member, annotations);
    return bindingAnnotation == null ? Key.get(type) : Key.get(type, bindingAnnotation);
  }

  @Override
  public boolean equals(Object o) {
    return o instanceof ProviderMethodsModule
        && ((ProviderMethodsModule) o).delegate == delegate
        && ((ProviderMethodsModule) o).scanner == scanner;
  }

  @Override
  public int hashCode() {
    return delegate.hashCode();
  }
}


/*
 * Copyright (C) 2006 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.inject.name;

import com.google.inject.Binder;
import com.google.inject.Key;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;

/**
 * Utility methods for use with {@code @}{@link Named}.
 *
 * @author crazybob@google.com (Bob Lee)
 */
public class Names {

  private Names() {}

  /** Creates a {@link Named} annotation with {@code name} as the value. */
  public static Named named(String name) {
    return new NamedImpl(name);
  }

  /** Creates a constant binding to {@code @Named(key)} for each entry in {@code properties}. */
  public static void bindProperties(Binder binder, Map<String, String> properties) {
    binder = binder.skipSources(Names.class);
    for (Map.Entry<String, String> entry : properties.entrySet()) {
      String key = entry.getKey();
      String value = entry.getValue();
      binder.bind(Key.get(String.class, new NamedImpl(key))).toInstance(value);
    }
  }

  /**
   * Creates a constant binding to {@code @Named(key)} for each property. This method binds all
   * properties including those inherited from {@link Properties#defaults defaults}.
   */
  public static void bindProperties(Binder binder, Properties properties) {
    binder = binder.skipSources(Names.class);

    // use enumeration to include the default properties
    for (Enumeration<?> e = properties.propertyNames(); e.hasMoreElements(); ) {
      String propertyName = (String) e.nextElement();
      String value = properties.getProperty(propertyName);
      binder.bind(Key.get(String.class, new NamedImpl(propertyName))).toInstance(value);
    }
  }
}


/*
 * Copyright (C) 2007 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.inject;

import com.google.inject.internal.InternalInjectorCreator;
import java.util.Arrays;

/**
 * The entry point to the Guice framework. Creates {@link Injector}s from {@link Module}s.
 *
 *
Guice supports a model of development that draws clear boundaries between APIs,
 * Implementations of these APIs, Modules which configure these implementations, and finally
 * Applications which consist of a collection of Modules. It is the Application, which typically
 * defines your {@code main()} method, that bootstraps the Guice Injector using the {@code Guice}
 * class, as in this example:
 *
 *

 *     public class FooApplication {
 *       public static void main(String[] args) {
 *         Injector injector = Guice.createInjector(
 *             new ModuleA(),
 *             new ModuleB(),
 *             . . .
 *             new FooApplicationFlagsModule(args)
 *         );
 *
 *         // Now just bootstrap the application and you're done
 *         FooStarter starter = injector.getInstance(FooStarter.class);
 *         starter.runApplication();
 *       }
 *     }
 *

 */
public final class Guice {

  private Guice() {}

  /**
   * Creates an injector for the given set of modules. This is equivalent to calling {@link
   * #createInjector(Stage, Module...)} with Stage.DEVELOPMENT.
   *
   * @throws CreationException if one or more errors occur during injector construction
   */
  public static Injector createInjector(Module... modules) {
    return createInjector(Arrays.asList(modules));
  }

  /**
   * Creates an injector for the given set of modules. This is equivalent to calling {@link
   * #createInjector(Stage, Iterable)} with Stage.DEVELOPMENT.
   *
   * @throws CreationException if one or more errors occur during injector creation
   */
  public static Injector createInjector(Iterable<? extends Module> modules) {
    return createInjector(Stage.DEVELOPMENT, modules);
  }

  /**
   * Creates an injector for the given set of modules, in a given development stage.
   *
   * @throws CreationException if one or more errors occur during injector creation.
   */
  public static Injector createInjector(Stage stage, Module... modules) {
    return createInjector(stage, Arrays.asList(modules));
  }

  /**
   * Creates an injector for the given set of modules, in a given development stage.
   *
   * @throws CreationException if one or more errors occur during injector construction
   */
  public static Injector createInjector(Stage stage, Iterable<? extends Module> modules) {
    return new InternalInjectorCreator().stage(stage).addModules(modules).build();
  }
}


/*
 * Copyright (C) 2013 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.inject.spi;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.inject.internal.util.StackTraceElements;
import com.google.inject.internal.util.StackTraceElements.InMemoryStackTraceElement;
import java.util.List;

/**
 * Contains information about where and how an {@link Element element} was bound.
 *
 *
The {@link #getDeclaringSource() declaring source} refers to a location in source code that
 * defines the Guice {@link Element element}. For example, if the element is created from a method
 * annotated by {@literal @Provides}, the declaring source of element would be the method itself.
 *
 *
The {@link #getStackTrace()} refers to the sequence of calls ends at one of {@link
 * com.google.inject.Binder} {@code bindXXX()} methods and eventually defines the element. Note that
 * {@link #getStackTrace()} lists {@link StackTraceElement StackTraceElements} in reverse
 * chronological order. The first element (index zero) is the last method call and the last element
 * is the first method invocation. By default, the stack trace is not collected. The default
 * behavior can be changed by setting the {@code guice_include_stack_traces} flag value. The value
 * can be either {@code OFF}, {@code ONLY_FOR_DECLARING_SOURCE} or {@code COMPLETE}. Note that
 * collecting stack traces for every binding can cause a performance hit when the injector is
 * created.
 *
 *
The sequence of class names of {@link com.google.inject.Module modules} involved in the
 * element creation can be retrieved by {@link #getModuleClassNames()}. Similar to {@link
 * #getStackTrace()}, the order is reverse chronological. The first module (index 0) is the module
 * that installs the {@link Element element}. The last module is the root module.
 *
 *
In order to support the cases where a Guice {@link Element element} is created from another
 * Guice {@link Element element} (original) (e.g., by {@link Element#applyTo}), it also provides a
 * reference to the original element source ({@link #getOriginalElementSource()}).
 *
 * @since 4.0
 */
public final class ElementSource {

  /**
   * The {@link ElementSource source} of element that this element created from (if there is any),
   * otherwise {@code null}.
   */
  final ElementSource originalElementSource;

  /** The {@link ModuleSource source} of module creates the element. */
  final ModuleSource moduleSource;

  /**
   * The partial call stack that starts at the last module {@link Module#Configure(Binder)
   * configure(Binder)} call. The value is empty if stack trace collection is off.
   */
  final InMemoryStackTraceElement[] partialCallStack;

  /**
   * Refers to a single location in source code that causes the element creation. It can be any
   * object such as {@link Constructor}, {@link Method}, {@link Field}, {@link StackTraceElement},
   * etc. For example, if the element is created from a method annotated by {@literal @Provides},
   * the declaring source of element would be the method itself.
   */
  final Object declaringSource;

  /**
   * Creates a new {@ElementSource} from the given parameters.
   *
   * @param originalElementSource The source of element that this element created from (if there is
   *     any), otherwise {@code null}.
   * @param declaringSource the source (in)directly declared the element.
   * @param moduleSource the moduleSource when the element is bound
   * @param partialCallStack the partial call stack from the top module to where the element is
   *     bound
   */
  ElementSource(
      /* @Nullable */ ElementSource originalSource,
      Object declaringSource,
      ModuleSource moduleSource,
      StackTraceElement[] partialCallStack) {
    Preconditions.checkNotNull(declaringSource, "declaringSource cannot be null.");
    Preconditions.checkNotNull(moduleSource, "moduleSource cannot be null.");
    Preconditions.checkNotNull(partialCallStack, "partialCallStack cannot be null.");
    this.originalElementSource = originalSource;
    this.declaringSource = declaringSource;
    this.moduleSource = moduleSource;
    this.partialCallStack = StackTraceElements.convertToInMemoryStackTraceElement(partialCallStack);
  }

  /**
   * Returns the {@link ElementSource} of the element this was created or copied from. If this was
   * not created or copied from another element, returns {@code null}.
   */
  public ElementSource getOriginalElementSource() {
    return originalElementSource;
  }

  /**
   * Returns a single location in source code that defines the element. It can be any object such as
   * {@link java.lang.reflect.Constructor}, {@link java.lang.reflect.Method}, {@link
   * java.lang.reflect.Field}, {@link StackTraceElement}, etc. For example, if the element is
   * created from a method annotated by {@literal @Provides}, the declaring source of element would
   * be the method itself.
   */
  public Object getDeclaringSource() {
    return declaringSource;
  }

  /**
   * Returns the class names of modules involved in creating this {@link Element}. The first element
   * (index 0) is the class name of module that defined the element, and the last element is the
   * class name of root module.
   */
  public List<String> getModuleClassNames() {
    return moduleSource.getModuleClassNames();
  }

  /**
   * Returns the position of {@link com.google.inject.Module#configure configure(Binder)} method
   * call in the {@link #getStackTrace stack trace} for modules that their classes returned by
   * {@link #getModuleClassNames}. For example, if the stack trace looks like the following:
   *
   *

   *
{@code Binder.bind()}
   *
{@code ModuleTwo.configure()}
   *
{@code Binder.install()}
   *
{@code ModuleOne.configure()}
   *
{@code theRest().
   *

   *
   *
1 and 3 are returned.
   *
   *
In the cases where stack trace is not available (i.e., the stack trace was not collected),
   * it returns -1 for all module positions.
   */
  public List<Integer> getModuleConfigurePositionsInStackTrace() {
    int size = moduleSource.size();
    Integer[] positions = new Integer[size];
    int chunkSize = partialCallStack.length;
    positions[0] = chunkSize - 1;
    ModuleSource current = moduleSource;
    for (int cursor = 1; cursor < size; cursor++) {
      chunkSize = current.getPartialCallStackSize();
      positions[cursor] = positions[cursor - 1] + chunkSize;
      current = current.getParent();
    }
    return ImmutableList.<Integer>copyOf(positions);
  }

  /**
   * Returns the sequence of method calls that ends at one of {@link com.google.inject.Binder}
   * {@code bindXXX()} methods and eventually defines the element. Note that {@link #getStackTrace}
   * lists {@link StackTraceElement StackTraceElements} in reverse chronological order. The first
   * element (index zero) is the last method call and the last element is the first method
   * invocation. In the cases where stack trace is not available (i.e.,the stack trace was not
   * collected), it returns an empty array.
   */
  public StackTraceElement[] getStackTrace() {
    int modulesCallStackSize = moduleSource.getStackTraceSize();
    int chunkSize = partialCallStack.length;
    int size = moduleSource.getStackTraceSize() + chunkSize;
    StackTraceElement[] callStack = new StackTraceElement[size];
    System.arraycopy(
        StackTraceElements.convertToStackTraceElement(partialCallStack),
        0,
        callStack,
        0,
        chunkSize);
    System.arraycopy(moduleSource.getStackTrace(), 0, callStack, chunkSize, modulesCallStackSize);
    return callStack;
  }

  /** Returns {@code getDeclaringSource().toString()} value. */
  @Override
  public String toString() {
    return getDeclaringSource().toString();
  }
}


/*
 * Copyright (C) 2006 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.inject.internal.util;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.Map;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

/**
 * Looks up line numbers for classes and their members.
 *
 * @author Chris Nokleberg
 */
final class LineNumbers {

  private static final int ASM_API_LEVEL = Opcodes.ASM7;

  private final Class type;
  private final Map<String, Integer> lines = Maps.newHashMap();
  private String source;
  private int firstLine = Integer.MAX_VALUE;

  /**
   * Reads line number information from the given class, if available.
   *
   * @param type the class to read line number information from
   */
  public LineNumbers(Class type) throws IOException {
    this.type = type;

    if (!type.isArray()) {
      InputStream in = null;
      try {
        in = type.getResourceAsStream("/" + type.getName().replace('.', '/') + ".class");
      } catch (IllegalStateException ignored) {
        // Some classloaders throw IllegalStateException when they can't load a resource.
      }
      if (in != null) {
        try {
          new ClassReader(in).accept(new LineNumberReader(), ClassReader.SKIP_FRAMES);
        } catch (UnsupportedOperationException ignored) {
          // We may be trying to inspect classes that were compiled with a more recent version
          // of javac than our ASM supports.  If that happens, just ignore the class and don't
          // capture line numbers.
        } finally {
          try {
            in.close();
          } catch (IOException ignored) {
          }
        }
      }
    }
  }

  /**
   * Get the source file name as read from the bytecode.
   *
   * @return the source file name if available, or null
   */
  public String getSource() {
    return source;
  }

  /**
   * Get the line number associated with the given member.
   *
   * @param member a field, constructor, or method belonging to the class used during construction
   * @return the wrapped line number, or null if not available
   * @throws IllegalArgumentException if the member does not belong to the class used during
   *     construction
   */
  public Integer getLineNumber(Member member) {
    Preconditions.checkArgument(
        type == member.getDeclaringClass(),
        "Member %s belongs to %s, not %s",
        member,
        member.getDeclaringClass(),
        type);
    return lines.get(memberKey(member));
  }

  /** Gets the first line number. */
  public int getFirstLine() {
    return firstLine == Integer.MAX_VALUE ? 1 : firstLine;
  }

  private String memberKey(Member member) {
    checkNotNull(member, "member");

    /*if[AOP]*/
    if (member instanceof Field) {
      return member.getName();

    } else if (member instanceof Method) {
      return member.getName() + org.objectweb.asm.Type.getMethodDescriptor((Method) member);

    } else if (member instanceof Constructor) {
      StringBuilder sb = new StringBuilder().append("<init>(");
      for (Class param : ((Constructor) member).getParameterTypes()) {
        sb.append(org.objectweb.asm.Type.getDescriptor(param));
      }
      return sb.append(")V").toString();

    } else {
      throw new IllegalArgumentException(
          "Unsupported implementation class for Member, " + member.getClass());
    }
    /*end[AOP]*/
    /*if[NO_AOP]
    return "<NO_MEMBER_KEY>";
    end[NO_AOP]*/
  }

  private class LineNumberReader extends ClassVisitor {

    private int line = -1;
    private String pendingMethod;
    private String name;

    LineNumberReader() {
      super(ASM_API_LEVEL);
    }

    @Override
    public void visit(
        int version,
        int access,
        String name,
        String signature,
        String superName,
        String[] interfaces) {
      this.name = name;
    }

    @Override
    public MethodVisitor visitMethod(
        int access, String name, String desc, String signature, String[] exceptions) {
      if ((access & Opcodes.ACC_PRIVATE) != 0) {
        return null;
      }
      pendingMethod = name + desc;
      line = -1;
      return new LineNumberMethodVisitor();
    }

    @Override
    public void visitSource(String source, String debug) {
      LineNumbers.this.source = source;
    }

    public void visitLineNumber(int line, Label start) {
      if (line < firstLine) {
        firstLine = line;
      }

      this.line = line;
      if (pendingMethod != null) {
        lines.put(pendingMethod, line);
        pendingMethod = null;
      }
    }

    @Override
    public FieldVisitor visitField(
        int access, String name, String desc, String signature, Object value) {
      return null;
    }

    @Override
    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
      return new LineNumberAnnotationVisitor();
    }

    public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
      return new LineNumberAnnotationVisitor();
    }

    class LineNumberMethodVisitor extends MethodVisitor {
      LineNumberMethodVisitor() {
        super(ASM_API_LEVEL);
      }

      @Override
      public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
        return new LineNumberAnnotationVisitor();
      }

      @Override
      public AnnotationVisitor visitAnnotationDefault() {
        return new LineNumberAnnotationVisitor();
      }

      @Override
      public void visitFieldInsn(int opcode, String owner, String name, String desc) {
        if (opcode == Opcodes.PUTFIELD
            && LineNumberReader.this.name.equals(owner)
            && !lines.containsKey(name)
            && line != -1) {
          lines.put(name, line);
        }
      }

      @Override
      public void visitLineNumber(int line, Label start) {
        LineNumberReader.this.visitLineNumber(line, start);
      }
    }

    class LineNumberAnnotationVisitor extends AnnotationVisitor {
      LineNumberAnnotationVisitor() {
        super(ASM_API_LEVEL);
      }

      @Override
      public AnnotationVisitor visitAnnotation(String name, String desc) {
        return this;
      }

      @Override
      public AnnotationVisitor visitArray(String name) {
        return this;
      }

      public void visitLocalVariable(
          String name, String desc, String signature, Label start, Label end, int index) {}
    }
  }
}


/*
 * Copyright (C) 2009 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.inject.internal;

import com.google.common.collect.Lists;
import com.google.inject.Key;
import com.google.inject.MembersInjector;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.Element;
import com.google.inject.spi.MembersInjectorLookup;
import com.google.inject.spi.ProviderLookup;
import java.util.List;

/**
 * Returns providers and members injectors that haven't yet been initialized. As a part of injector
 * creation it's necessary to {@link #initialize initialize} these lookups.
 *
 * @author jessewilson@google.com (Jesse Wilson)
 */
final class DeferredLookups implements Lookups {
  private final InjectorImpl injector;
  private final List<Element> lookups = Lists.newArrayList();

  DeferredLookups(InjectorImpl injector) {
    this.injector = injector;
  }

  /** Initialize the specified lookups, either immediately or when the injector is created. */
  void initialize(Errors errors) {
    injector.lookups = injector;
    new LookupProcessor(errors).process(injector, lookups);
  }

  @Override
  public <T> Provider<T> getProvider(Key<T> key) {
    ProviderLookup<T> lookup = new ProviderLookup<>(key, key);
    lookups.add(lookup);
    return lookup.getProvider();
  }

  @Override
  public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> type) {
    MembersInjectorLookup<T> lookup = new MembersInjectorLookup<>(type, type);
    lookups.add(lookup);
    return lookup.getMembersInjector();
  }
}


/*
 * Copyright (C) 2006 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.inject.servlet;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.OutOfScopeException;
import com.google.inject.Provider;
import com.google.inject.Scope;
import com.google.inject.Scopes;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Servlet scopes.
 *
 * @author crazybob@google.com (Bob Lee)
 */
public class ServletScopes {

  private ServletScopes() {}

  /**
   * A threadlocal scope map for non-http request scopes. The {@link #REQUEST} scope falls back to
   * this scope map if no http request is available, and requires {@link #scopeRequest} to be called
   * as an alternative.
   */
  private static final ThreadLocal<Context> requestScopeContext = new ThreadLocal<>();

  /** A sentinel attribute value representing null. */
  enum NullObject {
    INSTANCE
  }

  /** HTTP servlet request scope. */
  public static final Scope REQUEST = new RequestScope();

  private static final class RequestScope implements Scope {
    @Override
    public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) {
      return new Provider<T>() {

        /** Keys bound in request-scope which are handled directly by GuiceFilter. */
        private final ImmutableSet<Key<?>> REQUEST_CONTEXT_KEYS =
            ImmutableSet.of(
                Key.get(HttpServletRequest.class),
                Key.get(HttpServletResponse.class),
                new Key<Map<String, String[]>>(RequestParameters.class) {});

        @Override
        public T get() {
          // Check if the alternate request scope should be used, if no HTTP
          // request is in progress.
          if (null == GuiceFilter.localContext.get()) {

            // NOTE(dhanji): We don't need to synchronize on the scope map
            // unlike the HTTP request because we're the only ones who have
            // a reference to it, and it is only available via a threadlocal.
            Context context = requestScopeContext.get();
            if (null != context) {
              @SuppressWarnings("unchecked")
              T t = (T) context.map.get(key);

              // Accounts for @Nullable providers.
              if (NullObject.INSTANCE == t) {
                return null;
              }

              if (t == null) {
                t = creator.get();
                if (!Scopes.isCircularProxy(t)) {
                  // Store a sentinel for provider-given null values.
                  context.map.put(key, t != null ? t : NullObject.INSTANCE);
                }
              }

              return t;
            } // else: fall into normal HTTP request scope and out of scope
            // exception is thrown.
          }

          // Always synchronize and get/set attributes on the underlying request
          // object since Filters may wrap the request and change the value of
          // {@code GuiceFilter.getRequest()}.
          //
          // This _correctly_ throws up if the thread is out of scope.
          HttpServletRequest request = GuiceFilter.getOriginalRequest(key);
          if (REQUEST_CONTEXT_KEYS.contains(key)) {
            // Don't store these keys as attributes, since they are handled by
            // GuiceFilter itself.
            return creator.get();
          }
          String name = key.toString();
          synchronized (request) {
            Object obj = request.getAttribute(name);
            if (NullObject.INSTANCE == obj) {
              return null;
            }
            @SuppressWarnings("unchecked")
            T t = (T) obj;
            if (t == null) {
              t = creator.get();
              if (!Scopes.isCircularProxy(t)) {
                request.setAttribute(name, (t != null) ? t : NullObject.INSTANCE);
              }
            }
            return t;
          }
        }

        @Override
        public String toString() {
          return String.format("%s[%s]", creator, REQUEST);
        }
      };
    }

    @Override
    public String toString() {
      return "ServletScopes.REQUEST";
    }
  }

  /** HTTP session scope. */
  public static final Scope SESSION = new SessionScope();

  private static final class SessionScope implements Scope {
    @Override
    public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) {
      final String name = key.toString();
      return new Provider<T>() {
        @Override
        public T get() {
          HttpSession session = GuiceFilter.getRequest(key).getSession();
          synchronized (session) {
            Object obj = session.getAttribute(name);
            if (NullObject.INSTANCE == obj) {
              return null;
            }
            @SuppressWarnings("unchecked")
            T t = (T) obj;
            if (t == null) {
              t = creator.get();
              if (!Scopes.isCircularProxy(t)) {
                session.setAttribute(name, (t != null) ? t : NullObject.INSTANCE);
              }
            }
            return t;
          }
        }

        @Override
        public String toString() {
          return String.format("%s[%s]", creator, SESSION);
        }
      };
    }

    @Override
    public String toString() {
      return "ServletScopes.SESSION";
    }
  }

  /**
   * Wraps the given callable in a contextual callable that "continues" the HTTP request in another
   * thread. This acts as a way of transporting request context data from the request processing
   * thread to to worker threads.
   *
   *
There are some limitations:
   *
   *

   *
Derived objects (i.e. anything marked @RequestScoped will not be transported.
   *
State changes to the HttpServletRequest after this method is called will not be seen in the
   *     continued thread.
   *
Only the HttpServletRequest, ServletContext and request parameter map are available in the
   *     continued thread. The response and session are not available.
   *

   *
   *
The returned callable will throw a {@link ScopingException} when called if the HTTP request
   * scope is still active on the current thread.
   *
   * @param callable code to be executed in another thread, which depends on the request scope.
   * @param seedMap the initial set of scoped instances for Guice to seed the request scope with. To
   *     seed a key with null, use {@code null} as the value.
   * @return a callable that will invoke the given callable, making the request context available to
   *     it.
   * @throws OutOfScopeException if this method is called from a non-request thread, or if the
   *     request has completed.
   * @since 3.0
   * @deprecated You probably want to use {@code transferRequest} instead
   */
  @Deprecated
  public static <T> Callable<T> continueRequest(Callable<T> callable, Map<Key<?>, Object> seedMap) {
    return wrap(callable, continueRequest(seedMap));
  }

  private static RequestScoper continueRequest(Map<Key<?>, Object> seedMap) {
    Preconditions.checkArgument(
        null != seedMap, "Seed map cannot be null, try passing in Collections.emptyMap() instead.");

    // Snapshot the seed map and add all the instances to our continuing HTTP request.
    final ContinuingHttpServletRequest continuingRequest =
        new ContinuingHttpServletRequest(GuiceFilter.getRequest(Key.get(HttpServletRequest.class)));
    for (Map.Entry<Key<?>, Object> entry : seedMap.entrySet()) {
      Object value = validateAndCanonicalizeValue(entry.getKey(), entry.getValue());
      continuingRequest.setAttribute(entry.getKey().toString(), value);
    }

    return new RequestScoper() {
      @Override
      public CloseableScope open() {
        checkScopingState(
            null == GuiceFilter.localContext.get(),
            "Cannot continue request in the same thread as a HTTP request!");
        return new GuiceFilter.Context(continuingRequest, continuingRequest, null).open();
      }
    };
  }

  /**
   * Wraps the given callable in a contextual callable that "transfers" the request to another
   * thread. This acts as a way of transporting request context data from the current thread to a
   * future thread.
   *
   *
As opposed to {@link #continueRequest}, this method propagates all existing scoped objects.
   * The primary use case is in server implementations where you can detach the request processing
   * thread while waiting for data, and reattach to a different thread to finish processing at a
   * later time.
   *
   *
Because request-scoped objects are not typically thread-safe, the callable returned by this
   * method must not be run on a different thread until the current request scope has terminated.
   * The returned callable will block until the current thread has released the request scope.
   *
   * @param callable code to be executed in another thread, which depends on the request scope.
   * @return a callable that will invoke the given callable, making the request context available to
   *     it.
   * @throws OutOfScopeException if this method is called from a non-request thread, or if the
   *     request has completed.
   * @since 4.0
   */
  public static <T> Callable<T> transferRequest(Callable<T> callable) {
    return wrap(callable, transferRequest());
  }

  /**
   * Returns an object that "transfers" the request to another thread. This acts as a way of
   * transporting request context data from the current thread to a future thread. The transferred
   * scope is the one active for the thread that calls this method. A later call to {@code open()}
   * activates the transferred the scope, including propagating any objects scoped at that time.
   *
   *
As opposed to {@link #continueRequest}, this method propagates all existing scoped objects.
   * The primary use case is in server implementations where you can detach the request processing
   * thread while waiting for data, and reattach to a different thread to finish processing at a
   * later time.
   *
   *
Because request-scoped objects are not typically thread-safe, it is important to avoid
   * applying the same request scope concurrently. The returned Scoper will block on open until the
   * current thread has released the request scope.
   *
   * @return an object that when opened will initiate the request scope
   * @throws OutOfScopeException if this method is called from a non-request thread, or if the
   *     request has completed.
   * @since 4.1
   */
  public static RequestScoper transferRequest() {
    return (GuiceFilter.localContext.get() != null)
        ? transferHttpRequest()
        : transferNonHttpRequest();
  }

  private static RequestScoper transferHttpRequest() {
    final GuiceFilter.Context context = GuiceFilter.localContext.get();
    if (context == null) {
      throw new OutOfScopeException("Not in a request scope");
    }
    return context;
  }

  private static RequestScoper transferNonHttpRequest() {
    final Context context = requestScopeContext.get();
    if (context == null) {
      throw new OutOfScopeException("Not in a request scope");
    }
    return context;
  }

  /**
   * Returns true if {@code binding} is request-scoped. If the binding is a {@link
   * com.google.inject.spi.LinkedKeyBinding linked key binding} and belongs to an injector (i. e. it
   * was retrieved via {@link Injector#getBinding Injector.getBinding()}), then this method will
   * also return true if the target binding is request-scoped.
   *
   * @since 4.0
   */
  public static boolean isRequestScoped(Binding<?> binding) {
    return Scopes.isScoped(binding, ServletScopes.REQUEST, RequestScoped.class);
  }

  /**
   * Scopes the given callable inside a request scope. This is not the same as the HTTP request
   * scope, but is used if no HTTP request scope is in progress. In this way, keys can be scoped
   * as @RequestScoped and exist in non-HTTP requests (for example: RPC requests) as well as in HTTP
   * request threads.
   *
   *
The returned callable will throw a {@link ScopingException} when called if there is a
   * request scope already active on the current thread.
   *
   * @param callable code to be executed which depends on the request scope. Typically in another
   *     thread, but not necessarily so.
   * @param seedMap the initial set of scoped instances for Guice to seed the request scope with. To
   *     seed a key with null, use {@code null} as the value.
   * @return a callable that when called will run inside the a request scope that exposes the
   *     instances in the {@code seedMap} as scoped keys.
   * @since 3.0
   */
  public static <T> Callable<T> scopeRequest(Callable<T> callable, Map<Key<?>, Object> seedMap) {
    return wrap(callable, scopeRequest(seedMap));
  }

  /**
   * Returns an object that will apply request scope to a block of code. This is not the same as the
   * HTTP request scope, but is used if no HTTP request scope is in progress. In this way, keys can
   * be scoped as @RequestScoped and exist in non-HTTP requests (for example: RPC requests) as well
   * as in HTTP request threads.
   *
   *
The returned object will throw a {@link ScopingException} when opened if there is a request
   * scope already active on the current thread.
   *
   * @param seedMap the initial set of scoped instances for Guice to seed the request scope with. To
   *     seed a key with null, use {@code null} as the value.
   * @return an object that when opened will initiate the request scope
   * @since 4.1
   */
  public static RequestScoper scopeRequest(Map<Key<?>, Object> seedMap) {
    Preconditions.checkArgument(
        null != seedMap, "Seed map cannot be null, try passing in Collections.emptyMap() instead.");

    // Copy the seed values into our local scope map.
    final Context context = new Context();
    Map<Key<?>, Object> validatedAndCanonicalizedMap =
        Maps.transformEntries(seedMap, ServletScopes::validateAndCanonicalizeValue);
    context.map.putAll(validatedAndCanonicalizedMap);
    return new RequestScoper() {
      @Override
      public CloseableScope open() {
        checkScopingState(
            null == GuiceFilter.localContext.get(),
            "An HTTP request is already in progress, cannot scope a new request in this thread.");
        checkScopingState(
            null == requestScopeContext.get(),
            "A request scope is already in progress, cannot scope a new request in this thread.");
        return context.open();
      }
    };
  }

  /**
   * Validates the key and object, ensuring the value matches the key type, and canonicalizing null
   * objects to the null sentinel.
   */
  private static Object validateAndCanonicalizeValue(Key<?> key, Object object) {
    if (object == null || object == NullObject.INSTANCE) {
      return NullObject.INSTANCE;
    }

    if (!key.getTypeLiteral().getRawType().isInstance(object)) {
      throw new IllegalArgumentException(
          "Value["
              + object
              + "] of type["
              + object.getClass().getName()
              + "] is not compatible with key["
              + key
              + "]");
    }

    return object;
  }

  private static class Context implements RequestScoper {
    final Map<Key, Object> map = Maps.newHashMap();

    // Synchronized to prevent two threads from using the same request
    // scope concurrently.
    final Lock lock = new ReentrantLock();

    @Override
    public CloseableScope open() {
      lock.lock();
      final Context previous = requestScopeContext.get();
      requestScopeContext.set(this);
      return new CloseableScope() {
        @Override
        public void close() {
          requestScopeContext.set(previous);
          lock.unlock();
        }
      };
    }
  }

  private static void checkScopingState(boolean condition, String msg) {
    if (!condition) {
      throw new ScopingException(msg);
    }
  }

  private static final <T> Callable<T> wrap(
      final Callable<T> delegate, final RequestScoper requestScoper) {
    return () -> {
      RequestScoper.CloseableScope scope = requestScoper.open();
      try {
        return delegate.call();
      } finally {
        scope.close();
      }
    };
  }
}


/*
 * Copyright (C) 2009 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.inject.internal;

import static com.google.common.collect.ImmutableListMultimap.flatteningToImmutableListMultimap;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.inject.ConfigurationException;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.TypeListener;
import com.google.inject.spi.TypeListenerBinding;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

/**
 * Members injectors by type.
 *
 * @author jessewilson@google.com (Jesse Wilson)
 */
final class MembersInjectorStore {
  private final InjectorImpl injector;
  private final ImmutableList<TypeListenerBinding> typeListenerBindings;

  private final FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>> cache =
      new FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>>() {
        @Override
        protected MembersInjectorImpl<?> create(TypeLiteral<?> type, Errors errors)
            throws ErrorsException {
          return createWithListeners(type, errors);
        }
      };

  MembersInjectorStore(InjectorImpl injector, List<TypeListenerBinding> typeListenerBindings) {
    this.injector = injector;
    this.typeListenerBindings = ImmutableList.copyOf(typeListenerBindings);
  }

  /**
   * Returns true if any type listeners are installed. Other code may take shortcuts when there
   * aren't any type listeners.
   */
  public boolean hasTypeListeners() {
    return !typeListenerBindings.isEmpty();
  }

  /** Returns a new complete members injector with injection listeners registered. */
  @SuppressWarnings("unchecked") // the MembersInjector type always agrees with the passed type
  public <T> MembersInjectorImpl<T> get(TypeLiteral<T> key, Errors errors) throws ErrorsException {
    return (MembersInjectorImpl<T>) cache.get(key, errors);
  }

  /**
   * Purges a type literal from the cache. Use this only if the type is not actually valid for
   * binding and needs to be purged. (See issue 319 and
   * ImplicitBindingTest#testCircularJitBindingsLeaveNoResidue and
   * #testInstancesRequestingProvidersForThemselvesWithChildInjectors for examples of when this is
   * necessary.)
   *
   * <p>Returns true if the type was stored in the cache, false otherwise.
   */
  boolean remove(TypeLiteral<?> type) {
    return cache.remove(type);
  }

  /** Creates a new members injector and attaches both injection listeners and method aspects. */
  private <T> MembersInjectorImpl<T> createWithListeners(TypeLiteral<T> type, Errors errors)
      throws ErrorsException {
    int numErrorsBefore = errors.size();

    Set<InjectionPoint> injectionPoints;
    try {
      injectionPoints = InjectionPoint.forInstanceMethodsAndFields(type);
    } catch (ConfigurationException e) {
      errors.merge(e.getErrorMessages());
      injectionPoints = e.getPartialValue();
    }
    ImmutableList<SingleMemberInjector> injectors = getInjectors(injectionPoints, errors);
    errors.throwIfNewErrors(numErrorsBefore);

    EncounterImpl<T> encounter = new EncounterImpl<>(errors, injector.lookups);
    Set<TypeListener> alreadySeenListeners = Sets.newHashSet();
    for (TypeListenerBinding binding : typeListenerBindings) {
      TypeListener typeListener = binding.getListener();
      if (!alreadySeenListeners.contains(typeListener) && binding.getTypeMatcher().matches(type)) {
        alreadySeenListeners.add(typeListener);
        try {
          typeListener.hear(type, encounter);
        } catch (RuntimeException e) {
          errors.errorNotifyingTypeListener(binding, type, e);
        }
      }
    }
    encounter.invalidate();
    errors.throwIfNewErrors(numErrorsBefore);

    return new MembersInjectorImpl<T>(injector, type, encounter, injectors);
  }

  /** Returns the injectors for the specified injection points. */
  ImmutableList<SingleMemberInjector> getInjectors(
      Set<InjectionPoint> injectionPoints, Errors errors) {
    List<SingleMemberInjector> injectors = Lists.newArrayList();
    for (InjectionPoint injectionPoint : injectionPoints) {
      try {
        Errors errorsForMember =
            injectionPoint.isOptional()
                ? new Errors(injectionPoint)
                : errors.withSource(injectionPoint);
        SingleMemberInjector injector =
            injectionPoint.getMember() instanceof Field
                ? new SingleFieldInjector(this.injector, injectionPoint, errorsForMember)
                : new SingleMethodInjector(this.injector, injectionPoint, errorsForMember);
        injectors.add(injector);
      } catch (ErrorsException ignoredForNow) {
        // ignored for now
      }
    }
    return ImmutableList.copyOf(injectors);
  }

  ImmutableListMultimap<TypeLiteral<?>, InjectionPoint> getAllInjectionPoints() {
    return cache.asMap().entrySet().stream()
        .collect(
            flatteningToImmutableListMultimap(
                Entry::getKey, entry -> entry.getValue().getInjectionPoints().stream()));
  }
}


/*
 * Copyright (C) 2006 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.inject.servlet;

import com.google.common.base.Throwables;
import com.google.inject.Inject;
import com.google.inject.Key;
import com.google.inject.OutOfScopeException;
import com.google.inject.internal.Errors;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Apply this filter in web.xml above all other filters (typically), to all requests where you plan
 * to use servlet scopes. This is also needed in order to dispatch requests to injectable filters
 * and servlets:
 *
 *

 *  <filter>
 *    <filter-name>guiceFilter</filter-name>
 *    <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
 *  </filter>
 *
 *  <filter-mapping>
 *    <filter-name>guiceFilter</filter-name>
 *    <url-pattern>/*</url-pattern>
 *  </filter-mapping>
 *

 *
 * This filter must appear before every filter that makes use of Guice injection or servlet scopes
 * functionality. Typically, you will only register this filter in web.xml and register any other
 * filters (and servlets) using a {@link ServletModule}.
 *
 * @author crazybob@google.com (Bob Lee)
 * @author dhanji@gmail.com (Dhanji R. Prasanna)
 */
public class GuiceFilter implements Filter {
  static final ThreadLocal<Context> localContext = new ThreadLocal<>();
  static volatile FilterPipeline pipeline = new DefaultFilterPipeline();

  /** We allow both the static and dynamic versions of the pipeline to exist. */
  private final FilterPipeline injectedPipeline;

  /** Used to inject the servlets configured via {@link ServletModule} */
  static volatile WeakReference<ServletContext> servletContext =
      new WeakReference<ServletContext>(null);

  private static final String MULTIPLE_INJECTORS_WARNING =
      "Multiple Servlet injectors detected. This is a warning "
          + "indicating that you have more than one "
          + GuiceFilter.class.getSimpleName()
          + " running "
          + "in your web application. If this is deliberate, you may safely "
          + "ignore this message. If this is NOT deliberate however, "
          + "your application may not work as expected.";

  private static final Logger LOGGER = Logger.getLogger(GuiceFilter.class.getName());

  public GuiceFilter() {
    // Use the static FilterPipeline
    this(null);
  }

  @Inject
  GuiceFilter(FilterPipeline filterPipeline) {
    injectedPipeline = filterPipeline;
  }

  //VisibleForTesting
  @Inject
  static void setPipeline(FilterPipeline pipeline) {

    // This can happen if you create many injectors and they all have their own
    // servlet module. This is legal, caveat a small warning.
    if (GuiceFilter.pipeline instanceof ManagedFilterPipeline) {
      LOGGER.warning(MULTIPLE_INJECTORS_WARNING);
    }

    // We overwrite the default pipeline
    GuiceFilter.pipeline = pipeline;
  }

  //VisibleForTesting
  static void reset() {
    pipeline = new DefaultFilterPipeline();
    localContext.remove();
  }

  @Override
  public void doFilter(
      final ServletRequest servletRequest,
      final ServletResponse servletResponse,
      final FilterChain filterChain)
      throws IOException, ServletException {

    final FilterPipeline filterPipeline = getFilterPipeline();

    Context previous = GuiceFilter.localContext.get();
    HttpServletRequest request = (HttpServletRequest) servletRequest;
    HttpServletResponse response = (HttpServletResponse) servletResponse;
    HttpServletRequest originalRequest =
        (previous != null) ? previous.getOriginalRequest() : request;
    try {
      RequestScoper.CloseableScope scope = new Context(originalRequest, request, response).open();
      try {
        //dispatch across the servlet pipeline, ensuring web.xml's filterchain is honored
        filterPipeline.dispatch(servletRequest, servletResponse, filterChain);
      } finally {
        scope.close();
      }
    } catch (IOException e) {
      throw e;
    } catch (ServletException e) {
      throw e;
    } catch (Exception e) {
      Throwables.propagate(e);
    }
  }

  static HttpServletRequest getOriginalRequest(Key<?> key) {
    return getContext(key).getOriginalRequest();
  }

  static HttpServletRequest getRequest(Key<?> key) {
    return getContext(key).getRequest();
  }

  static HttpServletResponse getResponse(Key<?> key) {
    return getContext(key).getResponse();
  }

  static ServletContext getServletContext() {
    return servletContext.get();
  }

  private static Context getContext(Key<?> key) {
    Context context = localContext.get();
    if (context == null) {
      throw new OutOfScopeException(
          "Cannot access scoped ["
              + Errors.convert(key)
              + "]. Either we are not currently inside an HTTP Servlet request, or you may"
              + " have forgotten to apply "
              + GuiceFilter.class.getName()
              + " as a servlet filter for this request.");
    }
    return context;
  }

  static class Context implements RequestScoper {
    final HttpServletRequest originalRequest;
    final HttpServletRequest request;
    final HttpServletResponse response;

    // Synchronized to prevent two threads from using the same request
    // scope concurrently.
    final Lock lock = new ReentrantLock();

    Context(
        HttpServletRequest originalRequest,
        HttpServletRequest request,
        HttpServletResponse response) {
      this.originalRequest = originalRequest;
      this.request = request;
      this.response = response;
    }

    HttpServletRequest getOriginalRequest() {
      return originalRequest;
    }

    HttpServletRequest getRequest() {
      return request;
    }

    HttpServletResponse getResponse() {
      return response;
    }

    @Override
    public CloseableScope open() {
      lock.lock();
      final Context previous = localContext.get();
      localContext.set(this);
      return new CloseableScope() {
        @Override
        public void close() {
          localContext.set(previous);
          lock.unlock();
        }
      };
    }
  }

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
    final ServletContext servletContext = filterConfig.getServletContext();

    // Store servlet context in a weakreference, for injection
    GuiceFilter.servletContext = new WeakReference<>(servletContext);

    // In the default pipeline, this is a noop. However, if replaced
    // by a managed pipeline, a lazy init will be triggered the first time
    // dispatch occurs.
    FilterPipeline filterPipeline = getFilterPipeline();
    filterPipeline.initPipeline(servletContext);
  }

  @Override
  public void destroy() {

    try {
      // Destroy all registered filters & servlets in that order
      FilterPipeline filterPipeline = getFilterPipeline();
      filterPipeline.destroyPipeline();

    } finally {
      reset();
      servletContext.clear();
    }
  }

  private FilterPipeline getFilterPipeline() {
    // Prefer the injected pipeline, but fall back on the static one for web.xml users.
    return (null != injectedPipeline) ? injectedPipeline : pipeline;
  }
}


/*
 * Copyright (C) 2006 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.inject;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.inject.internal.Annotations.generateAnnotation;
import static com.google.inject.internal.Annotations.isAllDefaultMethods;

import com.google.inject.internal.Annotations;
import com.google.inject.internal.MoreTypes;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

/**
 * Binding key consisting of an injection type and an optional annotation. Matches the type and
 * annotation at a point of injection.
 *
 *
For example, {@code Key.get(Service.class, Transactional.class)} will match:
 *
 *

 *   {@literal @}Inject
 *   public void setService({@literal @}Transactional Service service) {
 *     ...
 *   }
 *

 *
 *
{@code Key} supports generic types via subclassing just like {@link TypeLiteral}.
 *
 *
Keys do not differentiate between primitive types (int, char, etc.) and their corresponding
 * wrapper types (Integer, Character, etc.). Primitive types will be replaced with their wrapper
 * types when keys are created.
 *
 * @author crazybob@google.com (Bob Lee)
 */
public class Key<T> {

  private final AnnotationStrategy annotationStrategy;

  private final TypeLiteral<T> typeLiteral;
  private final int hashCode;
  // This field is updated using the 'Data-Race-Ful' lazy intialization pattern
  // See http://jeremymanson.blogspot.com/2008/12/benign-data-races-in-java.html for a detailed
  // explanation.
  private String toString;

  /**
   * Constructs a new key. Derives the type from this class's type parameter.
   *
   *
Clients create an empty anonymous subclass. Doing so embeds the type parameter in the
   * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
   *
   *
Example usage for a binding of type {@code Foo} annotated with {@code @Bar}:
   *
   *
{@code new Key<Foo>(Bar.class) {}}.
   */
  @SuppressWarnings("unchecked")
  protected Key(Class<? extends Annotation> annotationType) {
    this.annotationStrategy = strategyFor(annotationType);
    this.typeLiteral =
        MoreTypes.canonicalizeForKey(
            (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
    this.hashCode = computeHashCode();
  }

  /**
   * Constructs a new key. Derives the type from this class's type parameter.
   *
   *
Clients create an empty anonymous subclass. Doing so embeds the type parameter in the
   * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
   *
   *
Example usage for a binding of type {@code Foo} annotated with {@code @Bar}:
   *
   *
{@code new Key<Foo>(new Bar()) {}}.
   */
  @SuppressWarnings("unchecked")
  protected Key(Annotation annotation) {
    // no usages, not test-covered
    this.annotationStrategy = strategyFor(annotation);
    this.typeLiteral =
        MoreTypes.canonicalizeForKey(
            (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
    this.hashCode = computeHashCode();
  }

  /**
   * Constructs a new key. Derives the type from this class's type parameter.
   *
   *
Clients create an empty anonymous subclass. Doing so embeds the type parameter in the
   * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
   *
   *
Example usage for a binding of type {@code Foo}:
   *
   *
{@code new Key<Foo>() {}}.
   */
  @SuppressWarnings("unchecked")
  protected Key() {
    this.annotationStrategy = NullAnnotationStrategy.INSTANCE;
    this.typeLiteral =
        MoreTypes.canonicalizeForKey(
            (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
    this.hashCode = computeHashCode();
  }

  /** Unsafe. Constructs a key from a manually specified type. */
  @SuppressWarnings("unchecked")
  private Key(Type type, AnnotationStrategy annotationStrategy) {
    this.annotationStrategy = annotationStrategy;
    this.typeLiteral = MoreTypes.canonicalizeForKey((TypeLiteral<T>) TypeLiteral.get(type));
    this.hashCode = computeHashCode();
  }

  /** Constructs a key from a manually specified type. */
  private Key(TypeLiteral<T> typeLiteral, AnnotationStrategy annotationStrategy) {
    this.annotationStrategy = annotationStrategy;
    this.typeLiteral = MoreTypes.canonicalizeForKey(typeLiteral);
    this.hashCode = computeHashCode();
  }

  /** Computes the hash code for this key. */
  private int computeHashCode() {
    return typeLiteral.hashCode() * 31 + annotationStrategy.hashCode();
  }

  /** Gets the key type. */
  public final TypeLiteral<T> getTypeLiteral() {
    return typeLiteral;
  }

  /** Gets the annotation type. */
  public final Class<? extends Annotation> getAnnotationType() {
    return annotationStrategy.getAnnotationType();
  }

  /** Gets the annotation. */
  public final Annotation getAnnotation() {
    return annotationStrategy.getAnnotation();
  }

  boolean hasAnnotationType() {
    return annotationStrategy.getAnnotationType() != null;
  }

  String getAnnotationName() {
    Annotation annotation = annotationStrategy.getAnnotation();
    if (annotation != null) {
      return annotation.toString();
    }

    // not test-covered
    return annotationStrategy.getAnnotationType().toString();
  }

  Class<? super T> getRawType() {
    return typeLiteral.getRawType();
  }

  /** Gets the key of this key's provider. */
  Key<Provider<T>> providerKey() {
    return ofType(typeLiteral.providerType());
  }

  @Override
  public final boolean equals(Object o) {
    if (o == this) {
      return true;
    }
    if (!(o instanceof Key<?>)) {
      return false;
    }
    Key<?> other = (Key<?>) o;
    return annotationStrategy.equals(other.annotationStrategy)
        && typeLiteral.equals(other.typeLiteral);
  }

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

  @Override
  public final String toString() {
    // Note: to not introduce dangerous data races the field should only be read once in this
    // method.
    String local = toString;
    if (local == null) {
      local = "Key[type=" + typeLiteral + ", annotation=" + annotationStrategy + "]";
      toString = local;
    }
    return local;
  }

  /** Gets a key for an injection type and an annotation strategy. */
  static <T> Key<T> get(Class<T> type, AnnotationStrategy annotationStrategy) {
    return new Key<T>(type, annotationStrategy);
  }

  /** Gets a key for an injection type. */
  public static <T> Key<T> get(Class<T> type) {
    return new Key<T>(type, NullAnnotationStrategy.INSTANCE);
  }

  /** Gets a key for an injection type and an annotation type. */
  public static <T> Key<T> get(Class<T> type, Class<? extends Annotation> annotationType) {
    return new Key<T>(type, strategyFor(annotationType));
  }

  /** Gets a key for an injection type and an annotation. */
  public static <T> Key<T> get(Class<T> type, Annotation annotation) {
    return new Key<T>(type, strategyFor(annotation));
  }

  /** Gets a key for an injection type. */
  public static Key<?> get(Type type) {
    return new Key<Object>(type, NullAnnotationStrategy.INSTANCE);
  }

  /** Gets a key for an injection type and an annotation type. */
  public static Key<?> get(Type type, Class<? extends Annotation> annotationType) {
    return new Key<Object>(type, strategyFor(annotationType));
  }

  /** Gets a key for an injection type and an annotation. */
  public static Key<?> get(Type type, Annotation annotation) {
    return new Key<Object>(type, strategyFor(annotation));
  }

  /** Gets a key for an injection type. */
  public static <T> Key<T> get(TypeLiteral<T> typeLiteral) {
    return new Key<T>(typeLiteral, NullAnnotationStrategy.INSTANCE);
  }

  /** Gets a key for an injection type and an annotation type. */
  public static <T> Key<T> get(
      TypeLiteral<T> typeLiteral, Class<? extends Annotation> annotationType) {
    return new Key<T>(typeLiteral, strategyFor(annotationType));
  }

  /** Gets a key for an injection type and an annotation. */
  public static <T> Key<T> get(TypeLiteral<T> typeLiteral, Annotation annotation) {
    return new Key<T>(typeLiteral, strategyFor(annotation));
  }

  /**
   * Returns a new key of the specified type with the same annotation as this key.
   *
   * @since 3.0
   */
  public <T> Key<T> ofType(Class<T> type) {
    return new Key<T>(type, annotationStrategy);
  }

  /**
   * Returns a new key of the specified type with the same annotation as this key.
   *
   * @since 3.0
   */
  public Key<?> ofType(Type type) {
    return new Key<Object>(type, annotationStrategy);
  }

  /**
   * Returns a new key of the specified type with the same annotation as this key.
   *
   * @since 3.0
   */
  public <T> Key<T> ofType(TypeLiteral<T> type) {
    return new Key<T>(type, annotationStrategy);
  }

  /**
   * Returns true if this key has annotation attributes.
   *
   * @since 3.0
   */
  public boolean hasAttributes() {
    return annotationStrategy.hasAttributes();
  }

  /**
   * Returns this key without annotation attributes, i.e. with only the annotation type.
   *
   * @since 3.0
   */
  public Key<T> withoutAttributes() {
    return new Key<T>(typeLiteral, annotationStrategy.withoutAttributes());
  }

  interface AnnotationStrategy {
    Annotation getAnnotation();

    Class<? extends Annotation> getAnnotationType();

    boolean hasAttributes();

    AnnotationStrategy withoutAttributes();
  }

  /** Gets the strategy for an annotation. */
  static AnnotationStrategy strategyFor(Annotation annotation) {
    checkNotNull(annotation, "annotation");
    Class<? extends Annotation> annotationType = annotation.annotationType();
    ensureRetainedAtRuntime(annotationType);
    ensureIsBindingAnnotation(annotationType);

    if (Annotations.isMarker(annotationType)) {
      return new AnnotationTypeStrategy(annotationType, annotation);
    }

    return new AnnotationInstanceStrategy(Annotations.canonicalizeIfNamed(annotation));
  }

  /** Gets the strategy for an annotation type. */
  static AnnotationStrategy strategyFor(Class<? extends Annotation> annotationType) {
    annotationType = Annotations.canonicalizeIfNamed(annotationType);
    if (isAllDefaultMethods(annotationType)) {
      return strategyFor(generateAnnotation(annotationType));
    }

    checkNotNull(annotationType, "annotation type");
    ensureRetainedAtRuntime(annotationType);
    ensureIsBindingAnnotation(annotationType);
    return new AnnotationTypeStrategy(annotationType, null);
  }

  private static void ensureRetainedAtRuntime(Class<? extends Annotation> annotationType) {
    checkArgument(
        Annotations.isRetainedAtRuntime(annotationType),
        "%s is not retained at runtime. Please annotate it with @Retention(RUNTIME).",
        annotationType.getName());
  }

  private static void ensureIsBindingAnnotation(Class<? extends Annotation> annotationType) {
    checkArgument(
        Annotations.isBindingAnnotation(annotationType),
        "%s is not a binding annotation. Please annotate it with @BindingAnnotation.",
        annotationType.getName());
  }

  static enum NullAnnotationStrategy implements AnnotationStrategy {
    INSTANCE;

    @Override
    public boolean hasAttributes() {
      return false;
    }

    @Override
    public AnnotationStrategy withoutAttributes() {
      throw new UnsupportedOperationException("Key already has no attributes.");
    }

    @Override
    public Annotation getAnnotation() {
      return null;
    }

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

    @Override
    public String toString() {
      return "[none]";
    }
  }

  // this class not test-covered
  static class AnnotationInstanceStrategy implements AnnotationStrategy {

    final Annotation annotation;

    AnnotationInstanceStrategy(Annotation annotation) {
      this.annotation = checkNotNull(annotation, "annotation");
    }

    @Override
    public boolean hasAttributes() {
      return true;
    }

    @Override
    public AnnotationStrategy withoutAttributes() {
      return new AnnotationTypeStrategy(getAnnotationType(), annotation);
    }

    @Override
    public Annotation getAnnotation() {
      return annotation;
    }

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

    @Override
    public boolean equals(Object o) {
      if (!(o instanceof AnnotationInstanceStrategy)) {
        return false;
      }

      AnnotationInstanceStrategy other = (AnnotationInstanceStrategy) o;
      return annotation.equals(other.annotation);
    }

    @Override
    public int hashCode() {
      return annotation.hashCode();
    }

    @Override
    public String toString() {
      return annotation.toString();
    }
  }

  static class AnnotationTypeStrategy implements AnnotationStrategy {

    final Class<? extends Annotation> annotationType;

    // Keep the instance around if we have it so the client can request it.
    final Annotation annotation;

    AnnotationTypeStrategy(Class<? extends Annotation> annotationType, Annotation annotation) {
      this.annotationType = checkNotNull(annotationType, "annotation type");
      this.annotation = annotation;
    }

    @Override
    public boolean hasAttributes() {
      return false;
    }

    @Override
    public AnnotationStrategy withoutAttributes() {
      throw new UnsupportedOperationException("Key already has no attributes.");
    }

    @Override
    public Annotation getAnnotation() {
      return annotation;
    }

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

    @Override
    public boolean equals(Object o) {
      if (!(o instanceof AnnotationTypeStrategy)) {
        return false;
      }

      AnnotationTypeStrategy other = (AnnotationTypeStrategy) o;
      return annotationType.equals(other.annotationType);
    }

    @Override
    public int hashCode() {
      return annotationType.hashCode();
    }

    @Override
    public String toString() {
      return "@" + annotationType.getName();
    }
  }
}