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 
40 import junit.framework.TestCase;
41 
42 import java.lang.annotation.ElementType;
43 import java.lang.annotation.Retention;
44 import java.lang.annotation.Target;
45 import java.util.List;
46 import java.util.Map;
47 
48 /**
49  * Tests for {@link ServletScopes}.
50  *
51  * @author forster@google.com (Mike Forster)
52  */
53 public class ServletScopesTest extends TestCase {
testIsRequestScopedPositive()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 
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 = 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 
indexBindings(Iterable<Element> elements)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