/* * Copyright (C) 2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.inject.servlet; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.google.inject.Guice; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.OutOfScopeException; import com.google.inject.Provider; import com.google.inject.ProvisionException; import com.google.inject.Singleton; import com.google.inject.name.Named; import com.google.inject.name.Names; import java.io.IOException; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import javax.servlet.ServletException; import junit.framework.TestCase; /** Tests continuation of requests */ public class ScopeRequestIntegrationTest extends TestCase { private static final String A_VALUE = "thereaoskdao"; private static final String A_DIFFERENT_VALUE = "hiaoskd"; private static final String SHOULDNEVERBESEEN = "Shouldneverbeseen!"; public final void testNonHttpRequestScopedCallable() throws ServletException, IOException, InterruptedException, ExecutionException { ExecutorService executor = Executors.newSingleThreadExecutor(); // We use servlet module here because we want to test that @RequestScoped // behaves properly with the non-HTTP request scope logic. Injector injector = Guice.createInjector( new ServletModule() { @Override protected void configureServlets() { bindConstant().annotatedWith(Names.named(SomeObject.INVALID)).to(SHOULDNEVERBESEEN); bind(SomeObject.class).in(RequestScoped.class); } }); SomeObject someObject = new SomeObject(A_VALUE); OffRequestCallable offRequestCallable = injector.getInstance(OffRequestCallable.class); executor .submit( ServletScopes.scopeRequest( offRequestCallable, ImmutableMap.<Key<?>, Object>of(Key.get(SomeObject.class), someObject))) .get(); assertSame(injector.getInstance(OffRequestCallable.class), offRequestCallable); // Make sure the value was passed on. assertEquals(someObject.value, offRequestCallable.value); assertFalse(SHOULDNEVERBESEEN.equals(someObject.value)); // Now create a new request and assert that the scopes don't cross. someObject = new SomeObject(A_DIFFERENT_VALUE); executor .submit( ServletScopes.scopeRequest( offRequestCallable, ImmutableMap.<Key<?>, Object>of(Key.get(SomeObject.class), someObject))) .get(); assertSame(injector.getInstance(OffRequestCallable.class), offRequestCallable); // Make sure the value was passed on. assertEquals(someObject.value, offRequestCallable.value); assertFalse(SHOULDNEVERBESEEN.equals(someObject.value)); executor.shutdown(); executor.awaitTermination(2, TimeUnit.SECONDS); } public final void testWrongValueClasses() throws Exception { Injector injector = Guice.createInjector( new ServletModule() { @Override protected void configureServlets() { bindConstant().annotatedWith(Names.named(SomeObject.INVALID)).to(SHOULDNEVERBESEEN); bind(SomeObject.class).in(RequestScoped.class); } }); OffRequestCallable offRequestCallable = injector.getInstance(OffRequestCallable.class); try { ServletScopes.scopeRequest( offRequestCallable, ImmutableMap.<Key<?>, Object>of(Key.get(SomeObject.class), "Boo!")); fail(); } catch (IllegalArgumentException iae) { assertEquals( "Value[Boo!] of type[java.lang.String] is not compatible with key[" + Key.get(SomeObject.class) + "]", iae.getMessage()); } } public final void testNullReplacement() throws Exception { Injector injector = Guice.createInjector( new ServletModule() { @Override protected void configureServlets() { bindConstant().annotatedWith(Names.named(SomeObject.INVALID)).to(SHOULDNEVERBESEEN); bind(SomeObject.class).in(RequestScoped.class); } }); Callable<SomeObject> callable = injector.getInstance(Caller.class); try { assertNotNull(callable.call()); fail(); } catch (ProvisionException pe) { assertTrue(pe.getCause() instanceof OutOfScopeException); } // Validate that an actual null entry in the map results in a null injected object. Map<Key<?>, Object> map = Maps.newHashMap(); map.put(Key.get(SomeObject.class), null); callable = ServletScopes.scopeRequest(injector.getInstance(Caller.class), map); assertNull(callable.call()); } @RequestScoped public static class SomeObject { private static final String INVALID = "invalid"; @Inject public SomeObject(@Named(INVALID) String value) { this.value = value; } private final String value; } @Singleton public static class OffRequestCallable implements Callable<String> { @Inject Provider<SomeObject> someObject; public String value; @Override public String call() throws Exception { // Inside this request, we should always get the same instance. assertSame(someObject.get(), someObject.get()); value = someObject.get().value; assertFalse(SHOULDNEVERBESEEN.equals(value)); return value; } } private static class Caller implements Callable<SomeObject> { @Inject Provider<SomeObject> someObject; @Override public SomeObject call() throws Exception { return someObject.get(); } } }