1 /* 2 * Copyright (C) 2008 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.internal; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 21 import com.google.common.collect.ImmutableList; 22 import com.google.common.collect.ImmutableMap; 23 import com.google.common.collect.Lists; 24 import com.google.common.collect.Maps; 25 import com.google.inject.Binding; 26 import com.google.inject.Key; 27 import com.google.inject.Scope; 28 import com.google.inject.TypeLiteral; 29 import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding; 30 import com.google.inject.spi.ProvisionListenerBinding; 31 import com.google.inject.spi.ScopeBinding; 32 import com.google.inject.spi.TypeConverterBinding; 33 import com.google.inject.spi.TypeListenerBinding; 34 import java.lang.annotation.Annotation; 35 import java.util.Collections; 36 import java.util.List; 37 import java.util.Map; 38 import java.util.Set; 39 40 /** @author jessewilson@google.com (Jesse Wilson) */ 41 final class InheritingState implements State { 42 43 private final State parent; 44 45 // Must be a linked hashmap in order to preserve order of bindings in Modules. 46 private final Map<Key<?>, Binding<?>> explicitBindingsMutable = Maps.newLinkedHashMap(); 47 private final Map<Key<?>, Binding<?>> explicitBindings = 48 Collections.unmodifiableMap(explicitBindingsMutable); 49 private final Map<Class<? extends Annotation>, ScopeBinding> scopes = Maps.newHashMap(); 50 private final List<TypeConverterBinding> converters = Lists.newArrayList(); 51 /*if[AOP]*/ 52 private final List<MethodAspect> methodAspects = Lists.newArrayList(); 53 /*end[AOP]*/ 54 private final List<TypeListenerBinding> typeListenerBindings = Lists.newArrayList(); 55 private final List<ProvisionListenerBinding> provisionListenerBindings = Lists.newArrayList(); 56 private final List<ModuleAnnotatedMethodScannerBinding> scannerBindings = Lists.newArrayList(); 57 private final WeakKeySet blacklistedKeys; 58 private final Object lock; 59 InheritingState(State parent)60 InheritingState(State parent) { 61 this.parent = checkNotNull(parent, "parent"); 62 this.lock = (parent == State.NONE) ? this : parent.lock(); 63 this.blacklistedKeys = new WeakKeySet(lock); 64 } 65 66 @Override parent()67 public State parent() { 68 return parent; 69 } 70 71 @Override 72 @SuppressWarnings("unchecked") // we only put in BindingImpls that match their key types getExplicitBinding(Key<T> key)73 public <T> BindingImpl<T> getExplicitBinding(Key<T> key) { 74 Binding<?> binding = explicitBindings.get(key); 75 return binding != null ? (BindingImpl<T>) binding : parent.getExplicitBinding(key); 76 } 77 78 @Override getExplicitBindingsThisLevel()79 public Map<Key<?>, Binding<?>> getExplicitBindingsThisLevel() { 80 return explicitBindings; 81 } 82 83 @Override putBinding(Key<?> key, BindingImpl<?> binding)84 public void putBinding(Key<?> key, BindingImpl<?> binding) { 85 explicitBindingsMutable.put(key, binding); 86 } 87 88 @Override getScopeBinding(Class<? extends Annotation> annotationType)89 public ScopeBinding getScopeBinding(Class<? extends Annotation> annotationType) { 90 ScopeBinding scopeBinding = scopes.get(annotationType); 91 return scopeBinding != null ? scopeBinding : parent.getScopeBinding(annotationType); 92 } 93 94 @Override putScopeBinding(Class<? extends Annotation> annotationType, ScopeBinding scope)95 public void putScopeBinding(Class<? extends Annotation> annotationType, ScopeBinding scope) { 96 scopes.put(annotationType, scope); 97 } 98 99 @Override getConvertersThisLevel()100 public Iterable<TypeConverterBinding> getConvertersThisLevel() { 101 return converters; 102 } 103 104 @Override addConverter(TypeConverterBinding typeConverterBinding)105 public void addConverter(TypeConverterBinding typeConverterBinding) { 106 converters.add(typeConverterBinding); 107 } 108 109 @Override getConverter( String stringValue, TypeLiteral<?> type, Errors errors, Object source)110 public TypeConverterBinding getConverter( 111 String stringValue, TypeLiteral<?> type, Errors errors, Object source) { 112 TypeConverterBinding matchingConverter = null; 113 for (State s = this; s != State.NONE; s = s.parent()) { 114 for (TypeConverterBinding converter : s.getConvertersThisLevel()) { 115 if (converter.getTypeMatcher().matches(type)) { 116 if (matchingConverter != null) { 117 errors.ambiguousTypeConversion(stringValue, source, type, matchingConverter, converter); 118 } 119 matchingConverter = converter; 120 } 121 } 122 } 123 return matchingConverter; 124 } 125 126 /*if[AOP]*/ 127 @Override addMethodAspect(MethodAspect methodAspect)128 public void addMethodAspect(MethodAspect methodAspect) { 129 methodAspects.add(methodAspect); 130 } 131 132 @Override getMethodAspects()133 public ImmutableList<MethodAspect> getMethodAspects() { 134 return new ImmutableList.Builder<MethodAspect>() 135 .addAll(parent.getMethodAspects()) 136 .addAll(methodAspects) 137 .build(); 138 } 139 /*end[AOP]*/ 140 141 @Override addTypeListener(TypeListenerBinding listenerBinding)142 public void addTypeListener(TypeListenerBinding listenerBinding) { 143 typeListenerBindings.add(listenerBinding); 144 } 145 146 @Override getTypeListenerBindings()147 public List<TypeListenerBinding> getTypeListenerBindings() { 148 List<TypeListenerBinding> parentBindings = parent.getTypeListenerBindings(); 149 List<TypeListenerBinding> result = 150 Lists.newArrayListWithCapacity(parentBindings.size() + typeListenerBindings.size()); 151 result.addAll(parentBindings); 152 result.addAll(typeListenerBindings); 153 return result; 154 } 155 156 @Override addProvisionListener(ProvisionListenerBinding listenerBinding)157 public void addProvisionListener(ProvisionListenerBinding listenerBinding) { 158 provisionListenerBindings.add(listenerBinding); 159 } 160 161 @Override getProvisionListenerBindings()162 public List<ProvisionListenerBinding> getProvisionListenerBindings() { 163 List<ProvisionListenerBinding> parentBindings = parent.getProvisionListenerBindings(); 164 List<ProvisionListenerBinding> result = 165 Lists.newArrayListWithCapacity(parentBindings.size() + provisionListenerBindings.size()); 166 result.addAll(parentBindings); 167 result.addAll(provisionListenerBindings); 168 return result; 169 } 170 171 @Override addScanner(ModuleAnnotatedMethodScannerBinding scanner)172 public void addScanner(ModuleAnnotatedMethodScannerBinding scanner) { 173 scannerBindings.add(scanner); 174 } 175 176 @Override getScannerBindings()177 public List<ModuleAnnotatedMethodScannerBinding> getScannerBindings() { 178 List<ModuleAnnotatedMethodScannerBinding> parentBindings = parent.getScannerBindings(); 179 List<ModuleAnnotatedMethodScannerBinding> result = 180 Lists.newArrayListWithCapacity(parentBindings.size() + scannerBindings.size()); 181 result.addAll(parentBindings); 182 result.addAll(scannerBindings); 183 return result; 184 } 185 186 @Override blacklist(Key<?> key, State state, Object source)187 public void blacklist(Key<?> key, State state, Object source) { 188 parent.blacklist(key, state, source); 189 blacklistedKeys.add(key, state, source); 190 } 191 192 @Override isBlacklisted(Key<?> key)193 public boolean isBlacklisted(Key<?> key) { 194 return blacklistedKeys.contains(key); 195 } 196 197 @Override getSourcesForBlacklistedKey(Key<?> key)198 public Set<Object> getSourcesForBlacklistedKey(Key<?> key) { 199 return blacklistedKeys.getSources(key); 200 } 201 202 @Override lock()203 public Object lock() { 204 return lock; 205 } 206 207 @Override getScopes()208 public Map<Class<? extends Annotation>, Scope> getScopes() { 209 ImmutableMap.Builder<Class<? extends Annotation>, Scope> builder = ImmutableMap.builder(); 210 for (Map.Entry<Class<? extends Annotation>, ScopeBinding> entry : scopes.entrySet()) { 211 builder.put(entry.getKey(), entry.getValue().getScope()); 212 } 213 return builder.build(); 214 } 215 } 216