1/**
2 * Copyright (C) 2011 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.inject.servlet;
18
19import static com.google.inject.name.Names.named;
20import static java.lang.annotation.RetentionPolicy.RUNTIME;
21
22import com.google.common.collect.ImmutableMap;
23import com.google.inject.AbstractModule;
24import com.google.inject.Binding;
25import com.google.inject.Guice;
26import com.google.inject.Injector;
27import com.google.inject.Key;
28import com.google.inject.Module;
29import com.google.inject.PrivateModule;
30import com.google.inject.Provides;
31import com.google.inject.ScopeAnnotation;
32import com.google.inject.Scopes;
33import com.google.inject.Singleton;
34import com.google.inject.name.Named;
35import com.google.inject.spi.Element;
36import com.google.inject.spi.Elements;
37import com.google.inject.spi.PrivateElements;
38import com.google.inject.util.Providers;
39
40import junit.framework.TestCase;
41
42import java.lang.annotation.ElementType;
43import java.lang.annotation.Retention;
44import java.lang.annotation.Target;
45import java.util.List;
46import java.util.Map;
47
48/**
49 * Tests for {@link ServletScopes}.
50 *
51 * @author forster@google.com (Mike Forster)
52 */
53public class ServletScopesTest extends TestCase {
54  public void testIsRequestScopedPositive() {
55    final Key<String> a = Key.get(String.class, named("A"));
56    final Key<String> b = Key.get(String.class, named("B"));
57    final Key<String> c = Key.get(String.class, named("C"));
58    final Key<String> d = Key.get(String.class, named("D"));
59    final Key<Object> e = Key.get(Object.class, named("E"));
60    final Key<String> f = Key.get(String.class, named("F"));
61    final Key<String> g = Key.get(String.class, named("G"));
62
63    Module requestScopedBindings = new AbstractModule() {
64      @Override
65      protected void configure() {
66        bind(a).to(b);
67        bind(b).to(c);
68        bind(c).toProvider(Providers.of("c")).in(ServletScopes.REQUEST);
69        bind(d).toProvider(Providers.of("d")).in(RequestScoped.class);
70        bind(e).to(AnnotatedRequestScopedClass.class);
71        install(new PrivateModule() {
72          @Override
73          protected void configure() {
74            bind(f).toProvider(Providers.of("f")).in(RequestScoped.class);
75            expose(f);
76          }
77        });
78      }
79
80      @Provides
81      @Named("G")
82      @RequestScoped
83      String provideG() {
84        return "g";
85      }
86    };
87
88    @SuppressWarnings("unchecked") // we know the module contains only bindings
89    List<Element> moduleBindings = Elements.getElements(requestScopedBindings);
90    ImmutableMap<Key<?>, Binding<?>> map = indexBindings(moduleBindings);
91    // linked bindings are not followed by modules
92    assertFalse(ServletScopes.isRequestScoped(map.get(a)));
93    assertFalse(ServletScopes.isRequestScoped(map.get(b)));
94    assertTrue(ServletScopes.isRequestScoped(map.get(c)));
95    assertTrue(ServletScopes.isRequestScoped(map.get(d)));
96    // annotated classes are not followed by modules
97    assertFalse(ServletScopes.isRequestScoped(map.get(e)));
98    assertTrue(ServletScopes.isRequestScoped(map.get(f)));
99    assertTrue(ServletScopes.isRequestScoped(map.get(g)));
100
101    Injector injector = Guice.createInjector(requestScopedBindings, new ServletModule());
102    assertTrue(ServletScopes.isRequestScoped(injector.getBinding(a)));
103    assertTrue(ServletScopes.isRequestScoped(injector.getBinding(b)));
104    assertTrue(ServletScopes.isRequestScoped(injector.getBinding(c)));
105    assertTrue(ServletScopes.isRequestScoped(injector.getBinding(d)));
106    assertTrue(ServletScopes.isRequestScoped(injector.getBinding(e)));
107    assertTrue(ServletScopes.isRequestScoped(injector.getBinding(f)));
108    assertTrue(ServletScopes.isRequestScoped(injector.getBinding(g)));
109  }
110
111  public void testIsRequestScopedNegative() {
112    final Key<String> a = Key.get(String.class, named("A"));
113    final Key<String> b = Key.get(String.class, named("B"));
114    final Key<String> c = Key.get(String.class, named("C"));
115    final Key<String> d = Key.get(String.class, named("D"));
116    final Key<String> e = Key.get(String.class, named("E"));
117    final Key<String> f = Key.get(String.class, named("F"));
118    final Key<String> g = Key.get(String.class, named("G"));
119    final Key<String> h = Key.get(String.class, named("H"));
120    final Key<String> i = Key.get(String.class, named("I"));
121    final Key<String> j = Key.get(String.class, named("J"));
122
123    Module requestScopedBindings = new AbstractModule() {
124      @Override
125      protected void configure() {
126        bind(a).to(b);
127        bind(b).to(c);
128        bind(c).toProvider(Providers.of("c")).in(Scopes.NO_SCOPE);
129        bind(d).toInstance("d");
130        bind(e).toProvider(Providers.of("e")).asEagerSingleton();
131        bind(f).toProvider(Providers.of("f")).in(Scopes.SINGLETON);
132        bind(g).toProvider(Providers.of("g")).in(Singleton.class);
133        bind(h).toProvider(Providers.of("h")).in(CustomScoped.class);
134        bindScope(CustomScoped.class, Scopes.NO_SCOPE);
135        install(new PrivateModule() {
136          @Override
137          protected void configure() {
138            bind(i).toProvider(Providers.of("i")).in(CustomScoped.class);
139            expose(i);
140          }
141        });
142      }
143
144      @Provides
145      @Named("J")
146      @CustomScoped
147      String provideJ() {
148        return "j";
149      }
150    };
151
152    @SuppressWarnings("unchecked") // we know the module contains only bindings
153    List<Element> moduleBindings = Elements.getElements(requestScopedBindings);
154    ImmutableMap<Key<?>, Binding<?>> map = indexBindings(moduleBindings);
155    assertFalse(ServletScopes.isRequestScoped(map.get(a)));
156    assertFalse(ServletScopes.isRequestScoped(map.get(b)));
157    assertFalse(ServletScopes.isRequestScoped(map.get(c)));
158    assertFalse(ServletScopes.isRequestScoped(map.get(d)));
159    assertFalse(ServletScopes.isRequestScoped(map.get(e)));
160    assertFalse(ServletScopes.isRequestScoped(map.get(f)));
161    assertFalse(ServletScopes.isRequestScoped(map.get(g)));
162    assertFalse(ServletScopes.isRequestScoped(map.get(h)));
163    assertFalse(ServletScopes.isRequestScoped(map.get(i)));
164    assertFalse(ServletScopes.isRequestScoped(map.get(j)));
165
166    Injector injector = Guice.createInjector(requestScopedBindings);
167    assertFalse(ServletScopes.isRequestScoped(injector.getBinding(a)));
168    assertFalse(ServletScopes.isRequestScoped(injector.getBinding(b)));
169    assertFalse(ServletScopes.isRequestScoped(injector.getBinding(c)));
170    assertFalse(ServletScopes.isRequestScoped(injector.getBinding(d)));
171    assertFalse(ServletScopes.isRequestScoped(injector.getBinding(e)));
172    assertFalse(ServletScopes.isRequestScoped(injector.getBinding(f)));
173    assertFalse(ServletScopes.isRequestScoped(injector.getBinding(g)));
174    assertFalse(ServletScopes.isRequestScoped(injector.getBinding(h)));
175    assertFalse(ServletScopes.isRequestScoped(injector.getBinding(i)));
176    assertFalse(ServletScopes.isRequestScoped(injector.getBinding(j)));
177  }
178
179  @RequestScoped
180  static class AnnotatedRequestScopedClass {}
181
182  @Target({ ElementType.TYPE, ElementType.METHOD })
183  @Retention(RUNTIME)
184  @ScopeAnnotation
185  private @interface CustomScoped {}
186
187  private ImmutableMap<Key<?>, Binding<?>> indexBindings(Iterable<Element> elements) {
188    ImmutableMap.Builder<Key<?>, Binding<?>> builder = ImmutableMap.builder();
189    for (Element element : elements) {
190      if (element instanceof Binding) {
191        Binding<?> binding = (Binding<?>) element;
192        builder.put(binding.getKey(), binding);
193      } else if (element instanceof PrivateElements) {
194        PrivateElements privateElements = (PrivateElements) element;
195        Map<Key<?>, Binding<?>> privateBindings = indexBindings(privateElements.getElements());
196        for (Key<?> exposed : privateElements.getExposedKeys()) {
197          builder.put(exposed, privateBindings.get(exposed));
198        }
199      }
200    }
201    return builder.build();
202  }
203}
204