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 
17 package com.google.inject.servlet;
18 
19 import static com.google.inject.name.Names.named;
20 import static java.lang.annotation.RetentionPolicy.RUNTIME;
21 
22 import com.google.common.collect.ImmutableMap;
23 import com.google.inject.AbstractModule;
24 import com.google.inject.Binding;
25 import com.google.inject.Guice;
26 import com.google.inject.Injector;
27 import com.google.inject.Key;
28 import com.google.inject.Module;
29 import com.google.inject.PrivateModule;
30 import com.google.inject.Provides;
31 import com.google.inject.ScopeAnnotation;
32 import com.google.inject.Scopes;
33 import com.google.inject.Singleton;
34 import com.google.inject.name.Named;
35 import com.google.inject.spi.Element;
36 import com.google.inject.spi.Elements;
37 import com.google.inject.spi.PrivateElements;
38 import com.google.inject.util.Providers;
39 import java.lang.annotation.ElementType;
40 import java.lang.annotation.Retention;
41 import java.lang.annotation.Target;
42 import java.util.List;
43 import java.util.Map;
44 import junit.framework.TestCase;
45 
46 /**
47  * Tests for {@link ServletScopes}.
48  *
49  * @author forster@google.com (Mike Forster)
50  */
51 public class ServletScopesTest extends TestCase {
testIsRequestScopedPositive()52   public void testIsRequestScopedPositive() {
53     final Key<String> a = Key.get(String.class, named("A"));
54     final Key<String> b = Key.get(String.class, named("B"));
55     final Key<String> c = Key.get(String.class, named("C"));
56     final Key<String> d = Key.get(String.class, named("D"));
57     final Key<Object> e = Key.get(Object.class, named("E"));
58     final Key<String> f = Key.get(String.class, named("F"));
59     final Key<String> g = Key.get(String.class, named("G"));
60 
61     Module requestScopedBindings =
62         new AbstractModule() {
63           @Override
64           protected void configure() {
65             bind(a).to(b);
66             bind(b).to(c);
67             bind(c).toProvider(Providers.of("c")).in(ServletScopes.REQUEST);
68             bind(d).toProvider(Providers.of("d")).in(RequestScoped.class);
69             bind(e).to(AnnotatedRequestScopedClass.class);
70             install(
71                 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 
testIsRequestScopedNegative()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 =
124         new AbstractModule() {
125           @Override
126           protected void configure() {
127             bind(a).to(b);
128             bind(b).to(c);
129             bind(c).toProvider(Providers.of("c")).in(Scopes.NO_SCOPE);
130             bind(d).toInstance("d");
131             bind(e).toProvider(Providers.of("e")).asEagerSingleton();
132             bind(f).toProvider(Providers.of("f")).in(Scopes.SINGLETON);
133             bind(g).toProvider(Providers.of("g")).in(Singleton.class);
134             bind(h).toProvider(Providers.of("h")).in(CustomScoped.class);
135             bindScope(CustomScoped.class, Scopes.NO_SCOPE);
136             install(
137                 new PrivateModule() {
138                   @Override
139                   protected void configure() {
140                     bind(i).toProvider(Providers.of("i")).in(CustomScoped.class);
141                     expose(i);
142                   }
143                 });
144           }
145 
146           @Provides
147           @Named("J")
148           @CustomScoped
149           String provideJ() {
150             return "j";
151           }
152         };
153 
154     @SuppressWarnings("unchecked") // we know the module contains only bindings
155     List<Element> moduleBindings = Elements.getElements(requestScopedBindings);
156     ImmutableMap<Key<?>, Binding<?>> map = indexBindings(moduleBindings);
157     assertFalse(ServletScopes.isRequestScoped(map.get(a)));
158     assertFalse(ServletScopes.isRequestScoped(map.get(b)));
159     assertFalse(ServletScopes.isRequestScoped(map.get(c)));
160     assertFalse(ServletScopes.isRequestScoped(map.get(d)));
161     assertFalse(ServletScopes.isRequestScoped(map.get(e)));
162     assertFalse(ServletScopes.isRequestScoped(map.get(f)));
163     assertFalse(ServletScopes.isRequestScoped(map.get(g)));
164     assertFalse(ServletScopes.isRequestScoped(map.get(h)));
165     assertFalse(ServletScopes.isRequestScoped(map.get(i)));
166     assertFalse(ServletScopes.isRequestScoped(map.get(j)));
167 
168     Injector injector = Guice.createInjector(requestScopedBindings);
169     assertFalse(ServletScopes.isRequestScoped(injector.getBinding(a)));
170     assertFalse(ServletScopes.isRequestScoped(injector.getBinding(b)));
171     assertFalse(ServletScopes.isRequestScoped(injector.getBinding(c)));
172     assertFalse(ServletScopes.isRequestScoped(injector.getBinding(d)));
173     assertFalse(ServletScopes.isRequestScoped(injector.getBinding(e)));
174     assertFalse(ServletScopes.isRequestScoped(injector.getBinding(f)));
175     assertFalse(ServletScopes.isRequestScoped(injector.getBinding(g)));
176     assertFalse(ServletScopes.isRequestScoped(injector.getBinding(h)));
177     assertFalse(ServletScopes.isRequestScoped(injector.getBinding(i)));
178     assertFalse(ServletScopes.isRequestScoped(injector.getBinding(j)));
179   }
180 
181   @RequestScoped
182   static class AnnotatedRequestScopedClass {}
183 
184   @Target({ElementType.TYPE, ElementType.METHOD})
185   @Retention(RUNTIME)
186   @ScopeAnnotation
187   private @interface CustomScoped {}
188 
indexBindings(Iterable<Element> elements)189   private ImmutableMap<Key<?>, Binding<?>> indexBindings(Iterable<Element> elements) {
190     ImmutableMap.Builder<Key<?>, Binding<?>> builder = ImmutableMap.builder();
191     for (Element element : elements) {
192       if (element instanceof Binding) {
193         Binding<?> binding = (Binding<?>) element;
194         builder.put(binding.getKey(), binding);
195       } else if (element instanceof PrivateElements) {
196         PrivateElements privateElements = (PrivateElements) element;
197         Map<Key<?>, Binding<?>> privateBindings = indexBindings(privateElements.getElements());
198         for (Key<?> exposed : privateElements.getExposedKeys()) {
199           builder.put(exposed, privateBindings.get(exposed));
200         }
201       }
202     }
203     return builder.build();
204   }
205 }
206