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