• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 com.google.common.collect.ImmutableMap;
20 import com.google.common.collect.Maps;
21 import com.google.inject.Guice;
22 import com.google.inject.Inject;
23 import com.google.inject.Injector;
24 import com.google.inject.Key;
25 import com.google.inject.OutOfScopeException;
26 import com.google.inject.Provider;
27 import com.google.inject.ProvisionException;
28 import com.google.inject.Singleton;
29 import com.google.inject.name.Named;
30 import com.google.inject.name.Names;
31 import java.io.IOException;
32 import java.util.Map;
33 import java.util.concurrent.Callable;
34 import java.util.concurrent.ExecutionException;
35 import java.util.concurrent.ExecutorService;
36 import java.util.concurrent.Executors;
37 import java.util.concurrent.TimeUnit;
38 import javax.servlet.ServletException;
39 import junit.framework.TestCase;
40 
41 /** Tests continuation of requests */
42 
43 public class ScopeRequestIntegrationTest extends TestCase {
44   private static final String A_VALUE = "thereaoskdao";
45   private static final String A_DIFFERENT_VALUE = "hiaoskd";
46 
47   private static final String SHOULDNEVERBESEEN = "Shouldneverbeseen!";
48 
testNonHttpRequestScopedCallable()49   public final void testNonHttpRequestScopedCallable()
50       throws ServletException, IOException, InterruptedException, ExecutionException {
51     ExecutorService executor = Executors.newSingleThreadExecutor();
52 
53     // We use servlet module here because we want to test that @RequestScoped
54     // behaves properly with the non-HTTP request scope logic.
55     Injector injector =
56         Guice.createInjector(
57             new ServletModule() {
58               @Override
59               protected void configureServlets() {
60                 bindConstant().annotatedWith(Names.named(SomeObject.INVALID)).to(SHOULDNEVERBESEEN);
61                 bind(SomeObject.class).in(RequestScoped.class);
62               }
63             });
64 
65     SomeObject someObject = new SomeObject(A_VALUE);
66     OffRequestCallable offRequestCallable = injector.getInstance(OffRequestCallable.class);
67     executor
68         .submit(
69             ServletScopes.scopeRequest(
70                 offRequestCallable,
71                 ImmutableMap.<Key<?>, Object>of(Key.get(SomeObject.class), someObject)))
72         .get();
73 
74     assertSame(injector.getInstance(OffRequestCallable.class), offRequestCallable);
75 
76     // Make sure the value was passed on.
77     assertEquals(someObject.value, offRequestCallable.value);
78     assertFalse(SHOULDNEVERBESEEN.equals(someObject.value));
79 
80     // Now create a new request and assert that the scopes don't cross.
81     someObject = new SomeObject(A_DIFFERENT_VALUE);
82     executor
83         .submit(
84             ServletScopes.scopeRequest(
85                 offRequestCallable,
86                 ImmutableMap.<Key<?>, Object>of(Key.get(SomeObject.class), someObject)))
87         .get();
88 
89     assertSame(injector.getInstance(OffRequestCallable.class), offRequestCallable);
90 
91     // Make sure the value was passed on.
92     assertEquals(someObject.value, offRequestCallable.value);
93     assertFalse(SHOULDNEVERBESEEN.equals(someObject.value));
94     executor.shutdown();
95     executor.awaitTermination(2, TimeUnit.SECONDS);
96   }
97 
testWrongValueClasses()98   public final void testWrongValueClasses() throws Exception {
99     Injector injector =
100         Guice.createInjector(
101             new ServletModule() {
102               @Override
103               protected void configureServlets() {
104                 bindConstant().annotatedWith(Names.named(SomeObject.INVALID)).to(SHOULDNEVERBESEEN);
105                 bind(SomeObject.class).in(RequestScoped.class);
106               }
107             });
108 
109     OffRequestCallable offRequestCallable = injector.getInstance(OffRequestCallable.class);
110     try {
111       ServletScopes.scopeRequest(
112           offRequestCallable, ImmutableMap.<Key<?>, Object>of(Key.get(SomeObject.class), "Boo!"));
113       fail();
114     } catch (IllegalArgumentException iae) {
115       assertEquals(
116           "Value[Boo!] of type[java.lang.String] is not compatible with key["
117               + Key.get(SomeObject.class)
118               + "]",
119           iae.getMessage());
120     }
121   }
122 
testNullReplacement()123   public final void testNullReplacement() throws Exception {
124     Injector injector =
125         Guice.createInjector(
126             new ServletModule() {
127               @Override
128               protected void configureServlets() {
129                 bindConstant().annotatedWith(Names.named(SomeObject.INVALID)).to(SHOULDNEVERBESEEN);
130                 bind(SomeObject.class).in(RequestScoped.class);
131               }
132             });
133 
134     Callable<SomeObject> callable = injector.getInstance(Caller.class);
135     try {
136       assertNotNull(callable.call());
137       fail();
138     } catch (ProvisionException pe) {
139       assertTrue(pe.getCause() instanceof OutOfScopeException);
140     }
141 
142     // Validate that an actual null entry in the map results in a null injected object.
143     Map<Key<?>, Object> map = Maps.newHashMap();
144     map.put(Key.get(SomeObject.class), null);
145     callable = ServletScopes.scopeRequest(injector.getInstance(Caller.class), map);
146     assertNull(callable.call());
147   }
148 
149   @RequestScoped
150   public static class SomeObject {
151     private static final String INVALID = "invalid";
152 
153     @Inject
SomeObject(@amedINVALID) String value)154     public SomeObject(@Named(INVALID) String value) {
155       this.value = value;
156     }
157 
158     private final String value;
159   }
160 
161   @Singleton
162   public static class OffRequestCallable implements Callable<String> {
163     @Inject Provider<SomeObject> someObject;
164 
165     public String value;
166 
167     @Override
call()168     public String call() throws Exception {
169       // Inside this request, we should always get the same instance.
170       assertSame(someObject.get(), someObject.get());
171 
172       value = someObject.get().value;
173       assertFalse(SHOULDNEVERBESEEN.equals(value));
174 
175       return value;
176     }
177   }
178 
179   private static class Caller implements Callable<SomeObject> {
180     @Inject Provider<SomeObject> someObject;
181 
182     @Override
call()183     public SomeObject call() throws Exception {
184       return someObject.get();
185     }
186   }
187 }
188