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.checkArgument; 20 import static com.google.common.base.Preconditions.checkNotNull; 21 import static com.google.common.base.Preconditions.checkState; 22 23 import com.google.common.base.MoreObjects; 24 import com.google.common.collect.ImmutableList; 25 import com.google.common.collect.ImmutableMap; 26 import com.google.common.collect.Lists; 27 import com.google.common.collect.Maps; 28 import com.google.inject.Binder; 29 import com.google.inject.Injector; 30 import com.google.inject.Key; 31 import com.google.inject.PrivateBinder; 32 import com.google.inject.spi.Element; 33 import com.google.inject.spi.ElementVisitor; 34 import com.google.inject.spi.PrivateElements; 35 import java.util.List; 36 import java.util.Map; 37 import java.util.Set; 38 39 /** @author jessewilson@google.com (Jesse Wilson) */ 40 public final class PrivateElementsImpl implements PrivateElements { 41 42 /* 43 * This class acts as both a value object and as a builder. When getElements() is called, an 44 * immutable collection of elements is constructed and the original mutable list is nulled out. 45 * Similarly, the exposed keys are made immutable on access. 46 */ 47 48 private final Object source; 49 50 private List<Element> elementsMutable = Lists.newArrayList(); 51 private List<ExposureBuilder<?>> exposureBuilders = Lists.newArrayList(); 52 53 /** lazily instantiated */ 54 private ImmutableList<Element> elements; 55 56 /** lazily instantiated */ 57 private ImmutableMap<Key<?>, Object> exposedKeysToSources; 58 59 private Injector injector; 60 PrivateElementsImpl(Object source)61 public PrivateElementsImpl(Object source) { 62 this.source = checkNotNull(source, "source"); 63 } 64 65 @Override getSource()66 public Object getSource() { 67 return source; 68 } 69 70 @Override getElements()71 public List<Element> getElements() { 72 if (elements == null) { 73 elements = ImmutableList.copyOf(elementsMutable); 74 elementsMutable = null; 75 } 76 77 return elements; 78 } 79 80 @Override getInjector()81 public Injector getInjector() { 82 return injector; 83 } 84 initInjector(Injector injector)85 public void initInjector(Injector injector) { 86 checkState(this.injector == null, "injector already initialized"); 87 this.injector = checkNotNull(injector, "injector"); 88 } 89 90 @Override getExposedKeys()91 public Set<Key<?>> getExposedKeys() { 92 if (exposedKeysToSources == null) { 93 Map<Key<?>, Object> exposedKeysToSourcesMutable = Maps.newLinkedHashMap(); 94 for (ExposureBuilder<?> exposureBuilder : exposureBuilders) { 95 exposedKeysToSourcesMutable.put(exposureBuilder.getKey(), exposureBuilder.getSource()); 96 } 97 exposedKeysToSources = ImmutableMap.copyOf(exposedKeysToSourcesMutable); 98 exposureBuilders = null; 99 } 100 101 return exposedKeysToSources.keySet(); 102 } 103 104 @Override acceptVisitor(ElementVisitor<T> visitor)105 public <T> T acceptVisitor(ElementVisitor<T> visitor) { 106 return visitor.visit(this); 107 } 108 getElementsMutable()109 public List<Element> getElementsMutable() { 110 return elementsMutable; 111 } 112 addExposureBuilder(ExposureBuilder<?> exposureBuilder)113 public void addExposureBuilder(ExposureBuilder<?> exposureBuilder) { 114 exposureBuilders.add(exposureBuilder); 115 } 116 117 @Override applyTo(Binder binder)118 public void applyTo(Binder binder) { 119 PrivateBinder privateBinder = binder.withSource(source).newPrivateBinder(); 120 121 for (Element element : getElements()) { 122 element.applyTo(privateBinder); 123 } 124 125 getExposedKeys(); // ensure exposedKeysToSources is populated 126 for (Map.Entry<Key<?>, Object> entry : exposedKeysToSources.entrySet()) { 127 privateBinder.withSource(entry.getValue()).expose(entry.getKey()); 128 } 129 } 130 131 @Override getExposedSource(Key<?> key)132 public Object getExposedSource(Key<?> key) { 133 getExposedKeys(); // ensure exposedKeysToSources is populated 134 Object source = exposedKeysToSources.get(key); 135 checkArgument(source != null, "%s not exposed by %s.", key, this); 136 return source; 137 } 138 139 @Override toString()140 public String toString() { 141 return MoreObjects.toStringHelper(PrivateElements.class) 142 .add("exposedKeys", getExposedKeys()) 143 .add("source", getSource()) 144 .toString(); 145 } 146 } 147