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