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