• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2013 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.spi;
18 
19 import com.google.common.base.Preconditions;
20 import com.google.common.collect.ImmutableList;
21 import com.google.inject.Module;
22 import com.google.inject.internal.util.StackTraceElements;
23 import com.google.inject.internal.util.StackTraceElements.InMemoryStackTraceElement;
24 
25 import java.util.List;
26 
27 /**
28  * Associated to a {@link Module module}, provides the module class name, the parent module {@link
29  * ModuleSource source}, and the call stack that ends just before the module {@link
30  * Module#configure(Binder) configure(Binder)} method invocation.
31  */
32 final class ModuleSource {
33 
34   /**
35    * The class name of module that this {@link ModuleSource} associated to.
36    */
37   private final String moduleClassName;
38 
39   /**
40    * The parent {@link ModuleSource module source}.
41    */
42   private final ModuleSource parent;
43 
44   /**
45    * The chunk of call stack that starts from the parent module {@link Module#configure(Binder)
46    * configure(Binder)} call and ends just before the module {@link Module#configure(Binder)
47    * configure(Binder)} method invocation. For a module without a parent module the chunk starts
48    * from the bottom of call stack. The array is non-empty if stack trace collection is on.
49    */
50   private final InMemoryStackTraceElement[] partialCallStack;
51 
52   /**
53    * Creates a new {@link ModuleSource} with a {@literal null} parent.
54    * @param module the corresponding module
55    * @param partialCallStack the chunk of call stack that starts from the parent module {@link
56    * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
57    * Module#configure(Binder) configure(Binder)} method invocation
58    */
ModuleSource(Object module, StackTraceElement[] partialCallStack)59   ModuleSource(Object module, StackTraceElement[] partialCallStack) {
60     this(null, module, partialCallStack);
61   }
62 
63  /**
64    * Creates a new {@link ModuleSource} Object.
65    * @param parent the parent module {@link ModuleSource source}
66    * @param module the corresponding module
67    * @param partialCallStack the chunk of call stack that starts from the parent module {@link
68    * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
69    * Module#configure(Binder) configure(Binder)} method invocation
70    */
ModuleSource( ModuleSource parent, Object module, StackTraceElement[] partialCallStack)71   private ModuleSource(
72       /* @Nullable */ ModuleSource parent, Object module, StackTraceElement[] partialCallStack) {
73     Preconditions.checkNotNull(module, "module cannot be null.");
74     Preconditions.checkNotNull(partialCallStack, "partialCallStack cannot be null.");
75     this.parent = parent;
76     this.moduleClassName = module.getClass().getName();
77     this.partialCallStack = StackTraceElements.convertToInMemoryStackTraceElement(partialCallStack);
78   }
79 
80   /**
81    * Returns the corresponding module class name.
82    *
83    * @see Class#getName()
84    */
getModuleClassName()85   String getModuleClassName() {
86     return moduleClassName;
87   }
88 
89   /**
90    * Returns the chunk of call stack that starts from the parent module {@link
91    * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
92    * Module#configure(Binder) configure(Binder)} method invocation. The return array is non-empty
93    * only if stack trace collection is on.
94    */
getPartialCallStack()95   StackTraceElement[] getPartialCallStack() {
96     return StackTraceElements.convertToStackTraceElement(partialCallStack);
97   }
98 
99   /**
100    * Returns the size of partial call stack if stack trace collection is on otherwise zero.
101    */
getPartialCallStackSize()102   int getPartialCallStackSize() {
103     return partialCallStack.length;
104   }
105 
106   /**
107    * Creates and returns a child {@link ModuleSource} corresponding to the {@link Module module}.
108    * @param module the corresponding module
109    * @param partialCallStack the chunk of call stack that starts from the parent module {@link
110    * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
111    * Module#configure(Binder) configure(Binder)} method invocation
112    */
createChild(Object module, StackTraceElement[] partialCallStack)113   ModuleSource createChild(Object module, StackTraceElement[] partialCallStack) {
114     return new ModuleSource(this, module, partialCallStack);
115   }
116 
117   /**
118    * Returns the parent module {@link ModuleSource source}.
119    */
getParent()120   ModuleSource getParent() {
121     return parent;
122   }
123 
124   /**
125    * Returns the class names of modules in this module source. The first element (index 0) is filled
126    * by this object {@link #getModuleClassName()}. The second element is filled by the parent's
127    * {@link #getModuleClassName()} and so on.
128    */
getModuleClassNames()129   List<String> getModuleClassNames() {
130     ImmutableList.Builder<String> classNames = ImmutableList.builder();
131     ModuleSource current = this;
132     while (current != null) {
133       String className = current.moduleClassName;
134       classNames.add(className);
135       current = current.parent;
136     }
137     return classNames.build();
138   }
139 
140   /**
141    * Returns the size of {@link ModuleSource ModuleSources} chain (all parents) that ends at this
142    * object.
143    */
size()144   int size() {
145     if (parent == null) {
146       return 1;
147     }
148     return parent.size() + 1;
149   }
150 
151   /**
152    * Returns the size of call stack that ends just before the module {@link Module#configure(Binder)
153    * configure(Binder)} method invocation (see {@link #getStackTrace()}).
154    */
getStackTraceSize()155   int getStackTraceSize() {
156     if (parent == null) {
157       return partialCallStack.length;
158     }
159     return parent.getStackTraceSize() + partialCallStack.length;
160   }
161 
162   /**
163    * Returns the full call stack that ends just before the module {@link Module#configure(Binder)
164    * configure(Binder)} method invocation. The return array is non-empty if stack trace collection
165    * on.
166    */
getStackTrace()167   StackTraceElement[] getStackTrace() {
168     int stackTraceSize = getStackTraceSize();
169     StackTraceElement[] callStack = new StackTraceElement[stackTraceSize];
170     int cursor = 0;
171     ModuleSource current = this;
172     while (current != null) {
173       StackTraceElement[] chunk =
174           StackTraceElements.convertToStackTraceElement(current.partialCallStack);
175       int chunkSize = chunk.length;
176       System.arraycopy(chunk, 0, callStack, cursor, chunkSize);
177       current = current.parent;
178       cursor = cursor + chunkSize;
179     }
180     return callStack;
181   }
182 }
183