blob: 312428ef9647416ee75297255fb668ac6100ecf3 [file] [log] [blame]
limpbizkita67e39f2008-02-18 20:10:59 +00001/**
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
17package com.google.inject.commands;
18
limpbizkit7d9991e2008-06-17 02:49:18 +000019import static com.google.common.base.Preconditions.checkNotNull;
limpbizkit185d2a22008-06-16 07:22:47 +000020import com.google.common.collect.Lists;
21import com.google.common.collect.Sets;
22import com.google.inject.Binder;
23import com.google.inject.Key;
24import com.google.inject.Module;
25import com.google.inject.Provider;
26import com.google.inject.Scope;
27import com.google.inject.Stage;
28import com.google.inject.TypeLiteral;
limpbizkita67e39f2008-02-18 20:10:59 +000029import com.google.inject.binder.AnnotatedBindingBuilder;
30import com.google.inject.binder.AnnotatedConstantBindingBuilder;
31import com.google.inject.matcher.Matcher;
limpbizkit185d2a22008-06-16 07:22:47 +000032import com.google.inject.spi.Message;
limpbizkitd6967b92008-05-16 15:28:51 +000033import com.google.inject.spi.SourceProviders;
limpbizkita67e39f2008-02-18 20:10:59 +000034import com.google.inject.spi.TypeConverter;
limpbizkita67e39f2008-02-18 20:10:59 +000035import java.lang.annotation.Annotation;
36import java.lang.reflect.Method;
limpbizkit185d2a22008-06-16 07:22:47 +000037import java.util.Arrays;
38import java.util.Collections;
39import java.util.List;
40import java.util.Set;
41import org.aopalliance.intercept.MethodInterceptor;
limpbizkita67e39f2008-02-18 20:10:59 +000042
43/**
44 * Records commands executed by a module so they can be inspected or
45 * {@link CommandReplayer replayed}.
46 *
47 * @author jessewilson@google.com (Jesse Wilson)
48 */
49public final class CommandRecorder {
limpbizkit3d58d6b2008-03-08 16:11:47 +000050 private Stage currentStage = Stage.DEVELOPMENT;
limpbizkita67e39f2008-02-18 20:10:59 +000051 private final EarlyRequestsProvider earlyRequestsProvider;
52
limpbizkit3d58d6b2008-03-08 16:11:47 +000053 static {
54 SourceProviders.skip(RecordingBinder.class);
55 }
56
limpbizkita67e39f2008-02-18 20:10:59 +000057 /**
58 * @param earlyRequestsProvider satisfies requests to
59 * {@link Binder#getProvider} at module execution time. For modules that
60 * will be used to create an injector, use {@link FutureInjector}.
61 */
62 public CommandRecorder(EarlyRequestsProvider earlyRequestsProvider) {
63 this.earlyRequestsProvider = earlyRequestsProvider;
64 }
65
66 /**
limpbizkit3d58d6b2008-03-08 16:11:47 +000067 * Sets the stage reported by the binder.
68 */
69 public void setCurrentStage(Stage currentStage) {
70 this.currentStage = currentStage;
71 }
72
73 /**
limpbizkita67e39f2008-02-18 20:10:59 +000074 * Records the commands executed by {@code modules}.
75 */
76 public List<Command> recordCommands(Module... modules) {
77 return recordCommands(Arrays.asList(modules));
78 }
79
80 /**
81 * Records the commands executed by {@code modules}.
82 */
83 public List<Command> recordCommands(Iterable<Module> modules) {
84 RecordingBinder binder = new RecordingBinder();
85 for (Module module : modules) {
limpbizkit3d58d6b2008-03-08 16:11:47 +000086 binder.install(module);
limpbizkita67e39f2008-02-18 20:10:59 +000087 }
88 return Collections.unmodifiableList(binder.commands);
89 }
90
91 private class RecordingBinder implements Binder {
limpbizkit7d9991e2008-06-17 02:49:18 +000092 private final Set<Module> modules;
93 private final List<Command> commands;
94
95 private RecordingBinder() {
96 modules = Sets.newHashSet();
97 commands = Lists.newArrayList();
98 }
99
100 /**
101 * Creates a recording binder that's backed by the same configuration as
102 * {@code backingBinder}.
103 */
104 private RecordingBinder(RecordingBinder backingBinder) {
105 modules = backingBinder.modules;
106 commands = backingBinder.commands;
107 }
limpbizkita67e39f2008-02-18 20:10:59 +0000108
109 public void bindInterceptor(
110 Matcher<? super Class<?>> classMatcher,
111 Matcher<? super Method> methodMatcher,
112 MethodInterceptor... interceptors) {
limpbizkit7d9991e2008-06-17 02:49:18 +0000113 commands.add(new BindInterceptorCommand(getSource(), classMatcher, methodMatcher, interceptors));
limpbizkita67e39f2008-02-18 20:10:59 +0000114 }
115
116 public void bindScope(Class<? extends Annotation> annotationType, Scope scope) {
limpbizkit7d9991e2008-06-17 02:49:18 +0000117 commands.add(new BindScopeCommand(getSource(), annotationType, scope));
limpbizkita67e39f2008-02-18 20:10:59 +0000118 }
119
120 public void requestStaticInjection(Class<?>... types) {
limpbizkit7d9991e2008-06-17 02:49:18 +0000121 commands.add(new RequestStaticInjectionCommand(getSource(), types));
limpbizkita67e39f2008-02-18 20:10:59 +0000122 }
123
124 public void install(Module module) {
limpbizkit3d58d6b2008-03-08 16:11:47 +0000125 if (modules.add(module)) {
126 module.configure(this);
127 }
limpbizkita67e39f2008-02-18 20:10:59 +0000128 }
129
130 public Stage currentStage() {
limpbizkit3d58d6b2008-03-08 16:11:47 +0000131 return currentStage;
limpbizkita67e39f2008-02-18 20:10:59 +0000132 }
133
134 public void addError(String message, Object... arguments) {
limpbizkit7d9991e2008-06-17 02:49:18 +0000135 commands.add(new AddMessageErrorCommand(getSource(), message, arguments));
limpbizkita67e39f2008-02-18 20:10:59 +0000136 }
137
138 public void addError(Throwable t) {
limpbizkit7d9991e2008-06-17 02:49:18 +0000139 commands.add(new AddThrowableErrorCommand(getSource(), t));
limpbizkita67e39f2008-02-18 20:10:59 +0000140 }
141
limpbizkit185d2a22008-06-16 07:22:47 +0000142 public void addError(Message message) {
143 throw new UnsupportedOperationException("TODO");
144 }
145
limpbizkita67e39f2008-02-18 20:10:59 +0000146 public <T> BindCommand<T>.BindingBuilder bind(Key<T> key) {
limpbizkit7d9991e2008-06-17 02:49:18 +0000147 BindCommand<T> bindCommand = new BindCommand<T>(getSource(), key);
limpbizkita67e39f2008-02-18 20:10:59 +0000148 commands.add(bindCommand);
limpbizkit3d58d6b2008-03-08 16:11:47 +0000149 return bindCommand.bindingBuilder(RecordingBinder.this);
limpbizkita67e39f2008-02-18 20:10:59 +0000150 }
151
152 public <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) {
153 return bind(Key.get(typeLiteral));
154 }
155
156 public <T> AnnotatedBindingBuilder<T> bind(Class<T> type) {
157 return bind(Key.get(type));
158 }
159
160 public AnnotatedConstantBindingBuilder bindConstant() {
limpbizkit7d9991e2008-06-17 02:49:18 +0000161 BindConstantCommand bindConstantCommand = new BindConstantCommand(getSource());
limpbizkita67e39f2008-02-18 20:10:59 +0000162 commands.add(bindConstantCommand);
limpbizkit3d58d6b2008-03-08 16:11:47 +0000163 return bindConstantCommand.bindingBuilder(RecordingBinder.this);
limpbizkita67e39f2008-02-18 20:10:59 +0000164 }
165
166 public <T> Provider<T> getProvider(final Key<T> key) {
limpbizkit7d9991e2008-06-17 02:49:18 +0000167 commands.add(new GetProviderCommand<T>(getSource(), key, earlyRequestsProvider));
limpbizkita67e39f2008-02-18 20:10:59 +0000168 return new Provider<T>() {
169 public T get() {
170 return earlyRequestsProvider.get(key);
171 }
limpbizkitd6967b92008-05-16 15:28:51 +0000172
173 @Override public String toString() {
174 return "Provider<" + key.getTypeLiteral() + ">";
175 }
limpbizkita67e39f2008-02-18 20:10:59 +0000176 };
177 }
178
179 public <T> Provider<T> getProvider(Class<T> type) {
180 return getProvider(Key.get(type));
181 }
182
183 public void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
limpbizkit3d58d6b2008-03-08 16:11:47 +0000184 TypeConverter converter) {
limpbizkit7d9991e2008-06-17 02:49:18 +0000185 commands.add(new ConvertToTypesCommand(getSource(), typeMatcher, converter));
186 }
187
188 public Binder withSource(final Object source) {
189 checkNotNull(source, "source");
190
191 return new RecordingBinder(this) {
192 @Override protected Object getSource() {
193 return source;
194 }
195 };
196 }
197
198 protected Object getSource() {
199 return SourceProviders.defaultSource();
limpbizkita67e39f2008-02-18 20:10:59 +0000200 }
limpbizkitd6967b92008-05-16 15:28:51 +0000201
202 @Override public String toString() {
203 return "Binder";
204 }
limpbizkita67e39f2008-02-18 20:10:59 +0000205 }
206}