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
17package com.google.inject.spi;
18
19import com.google.common.base.Preconditions;
20import com.google.common.collect.ImmutableList;
21import com.google.inject.internal.util.StackTraceElements;
22import com.google.inject.internal.util.StackTraceElements.InMemoryStackTraceElement;
23
24import java.util.List;
25
26/**
27 * Contains information about where and how an {@link Element element} was
28 * bound.
29 * <p>
30 * The {@link #getDeclaringSource() declaring source} refers to a location in
31 * source code that defines the Guice {@link Element element}. For example, if
32 * the element is created from a method annotated by {@literal @Provides}, the
33 * declaring source of element would be the method itself.
34 * <p>
35 * The {@link #getStackTrace()} refers to the sequence of calls ends at one of
36 * {@link com.google.inject.Binder} {@code bindXXX()} methods and eventually
37 * defines the element. Note that {@link #getStackTrace()} lists
38 * {@link StackTraceElement StackTraceElements} in reverse chronological order.
39 * The first element (index zero) is the last method call and the last element
40 * is the first method invocation. By default, the stack trace is not collected.
41 * The default behavior can be changed by setting the
42 * {@code guice_include_stack_traces} flag value. The value can be either
43 * {@code OFF}, {@code ONLY_FOR_DECLARING_SOURCE} or {@code COMPLETE}. Note that
44 * collecting stack traces for every binding can cause a performance hit when
45 * the injector is created.
46 * <p>
47 * The sequence of class names of {@link com.google.inject.Module modules}
48 * involved in the element creation can be retrieved by
49 * {@link #getModuleClassNames()}. Similar to {@link #getStackTrace()}, the
50 * order is reverse chronological. The first module (index 0) is the module that
51 * installs the {@link Element element}. The last module is the root module.
52 * <p>
53 * In order to support the cases where a Guice {@link Element element} is
54 * created from another Guice {@link Element element} (original) (e.g., by
55 * {@link Element#applyTo}), it also provides a reference to the original
56 * element source ({@link #getOriginalElementSource()}).
57 *
58 * @since 4.0
59 */
60public final class ElementSource {
61
62  /**
63   * The {@link ElementSource source} of element that this element created from (if there is any),
64   * otherwise {@code null}.
65   */
66  final ElementSource originalElementSource;
67
68  /** The {@link ModuleSource source} of module creates the element. */
69  final ModuleSource moduleSource;
70
71  /**
72   * The partial call stack that starts at the last module {@link Module#Configure(Binder)
73   * configure(Binder)} call. The value is empty if stack trace collection is off.
74   */
75  final InMemoryStackTraceElement[] partialCallStack;
76
77  /**
78   * Refers to a single location in source code that causes the element creation. It can be any
79   * object such as {@link Constructor}, {@link Method}, {@link Field}, {@link StackTraceElement},
80   * etc. For example, if the element is created from a method annotated by {@literal @Provides},
81   * the declaring source of element would be the method itself.
82   */
83  final Object declaringSource;
84
85  /**
86   * Creates a new {@ElementSource} from the given parameters.
87   * @param originalElementSource The source of element that this element created from (if there is
88   * any), otherwise {@code null}.
89   * @param declaringSource the source (in)directly declared the element.
90   * @param moduleSource the moduleSource when the element is bound
91   * @param partialCallStack the partial call stack from the top module to where the element is
92   * bound
93   */
94  ElementSource(/* @Nullable */ ElementSource originalSource, Object declaringSource,
95      ModuleSource moduleSource, StackTraceElement[] partialCallStack) {
96    Preconditions.checkNotNull(declaringSource, "declaringSource cannot be null.");
97    Preconditions.checkNotNull(moduleSource, "moduleSource cannot be null.");
98    Preconditions.checkNotNull(partialCallStack, "partialCallStack cannot be null.");
99    this.originalElementSource = originalSource;
100    this.declaringSource = declaringSource;
101    this.moduleSource = moduleSource;
102    this.partialCallStack = StackTraceElements.convertToInMemoryStackTraceElement(partialCallStack);
103  }
104
105  /**
106   * Returns the {@link ElementSource} of the element this was created or copied from. If this was
107   * not created or copied from another element, returns {@code null}.
108   */
109  public ElementSource getOriginalElementSource() {
110    return originalElementSource;
111  }
112
113  /**
114   * Returns a single location in source code that defines the element. It can be any object
115   * such as {@link java.lang.reflect.Constructor}, {@link java.lang.reflect.Method},
116   * {@link java.lang.reflect.Field}, {@link StackTraceElement}, etc. For
117   * example, if the element is created from a method annotated by {@literal @Provides}, the
118   * declaring source of element would be the method itself.
119   */
120  public Object getDeclaringSource() {
121    return declaringSource;
122  }
123
124  /**
125   * Returns the class names of modules involved in creating this {@link Element}. The first
126   * element (index 0) is the class name of module that defined the element, and the last element
127   * is the class name of root module.
128   */
129  public List<String> getModuleClassNames() {
130    return moduleSource.getModuleClassNames();
131  }
132
133  /**
134   * Returns the position of {@link com.google.inject.Module#configure configure(Binder)} method
135   * call in the {@link #getStackTrace stack trace} for modules that their classes returned by
136   * {@link #getModuleClassNames}. For example, if the stack trace looks like the following:
137   * <p>
138   * {@code
139   *  0 - Binder.bind(),
140   *  1 - ModuleTwo.configure(),
141   *  2 - Binder.install(),
142   *  3 - ModuleOne.configure(),
143   *  4 - theRest().
144   * }
145   * <p>
146   * 1 and 3 are returned.
147   * <p>
148   * In the cases where stack trace is not available (i.e., the stack trace was not collected),
149   * it returns -1 for all module positions.
150   */
151  public List<Integer> getModuleConfigurePositionsInStackTrace() {
152    int size = moduleSource.size();
153    Integer[] positions = new Integer[size];
154    int chunkSize = partialCallStack.length;
155    positions[0] = chunkSize - 1;
156    ModuleSource current = moduleSource;
157    for (int cursor = 1; cursor < size; cursor++) {
158      chunkSize = current.getPartialCallStackSize();
159      positions[cursor] = positions[cursor - 1] + chunkSize;
160      current = current.getParent();
161    }
162    return ImmutableList.<Integer>copyOf(positions);
163  }
164
165  /**
166   * Returns the sequence of method calls that ends at one of {@link com.google.inject.Binder}
167   * {@code bindXXX()} methods and eventually defines the element. Note that
168   * {@link #getStackTrace} lists {@link StackTraceElement StackTraceElements} in reverse
169   * chronological order. The first element (index zero) is the last method call and the last
170   * element is the first method invocation. In the cases where stack trace is not available
171   * (i.e.,the stack trace was not collected), it returns an empty array.
172   */
173  public StackTraceElement[] getStackTrace() {
174    int modulesCallStackSize = moduleSource.getStackTraceSize();
175    int chunkSize = partialCallStack.length;
176    int size = moduleSource.getStackTraceSize() + chunkSize;
177    StackTraceElement[] callStack = new StackTraceElement[size];
178    System.arraycopy(
179        StackTraceElements.convertToStackTraceElement(partialCallStack), 0, callStack, 0,
180        chunkSize);
181    System.arraycopy(moduleSource.getStackTrace(), 0, callStack, chunkSize, modulesCallStackSize);
182    return callStack;
183  }
184
185  /**
186   * Returns {@code getDeclaringSource().toString()} value.
187   */
188  @Override
189  public String toString() {
190    return getDeclaringSource().toString();
191  }
192}
193