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