001 /*
002 * Copyright 2008-2015 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.codehaus.griffon.runtime.core.injection;
017
018 import griffon.core.injection.Binding;
019 import griffon.core.injection.InstanceBinding;
020 import griffon.core.injection.ProviderBinding;
021 import griffon.core.injection.ProviderTypeBinding;
022 import griffon.core.injection.TargetBinding;
023 import griffon.util.AnnotationUtils;
024
025 import javax.annotation.Nonnull;
026 import javax.annotation.Nullable;
027 import javax.inject.Provider;
028 import javax.inject.Qualifier;
029 import java.lang.annotation.Annotation;
030 import java.util.List;
031
032 import static griffon.util.AnnotationUtils.harvestQualifiers;
033 import static java.util.Objects.requireNonNull;
034
035 /**
036 * @author Andres Almiray
037 * @since 2.0.0
038 */
039 public class Bindings {
040 public static <T> AnnotatedBindingBuilder<T> bind(@Nonnull Class<T> clazz) {
041 requireNonNull(clazz, "Argument 'class' must not be null");
042 return new AnnotatedBindingBuilderImpl<>(clazz);
043 }
044
045 private static abstract class SingletonBindingBuilderImpl<T> implements SingletonBindingBuilder<T> {
046 protected boolean singleton;
047
048 @Override
049 public void asSingleton() {
050 singleton = true;
051 }
052 }
053
054 private abstract static class LinkedBindingBuilderImpl<T> extends SingletonBindingBuilderImpl<T> implements LinkedBindingBuilder<T> {
055 protected Class<? extends T> target;
056 protected T instance;
057 protected Provider<T> provider;
058 protected Class<? extends Provider<T>> providerType;
059
060 @Nonnull
061 @Override
062 public SingletonBindingBuilder<T> to(@Nonnull Class<? extends T> target) {
063 this.target = requireNonNull(target, "Argument 'target' must not be null");
064 return this;
065 }
066
067 @Override
068 public void toInstance(@Nonnull T instance) {
069 this.instance = requireNonNull(instance, "Argument 'instance' must not be null");
070 }
071
072 @Nonnull
073 @Override
074 public SingletonBindingBuilder<T> toProvider(@Nonnull Provider<T> provider) {
075 this.provider = requireNonNull(provider, "Argument 'provider' must not be null");
076 return this;
077 }
078
079 @Nonnull
080 @Override
081 public SingletonBindingBuilder<T> toProvider(@Nonnull Class<? extends Provider<T>> providerType) {
082 this.providerType = requireNonNull(providerType, "Argument 'providerType' must not be null");
083 return this;
084 }
085 }
086
087 private static class AnnotatedBindingBuilderImpl<T> extends LinkedBindingBuilderImpl<T> implements AnnotatedBindingBuilder<T> {
088 private final Class<T> source;
089 private Annotation classifier;
090 private Class<? extends Annotation> classifierType;
091
092 private AnnotatedBindingBuilderImpl(@Nonnull Class<T> source) {
093 this.source = requireNonNull(source, "Argument 'source' must not be null");
094 }
095
096 @Nonnull
097 @Override
098 public Binding<T> getBinding() {
099 if (instance != null) {
100 return classifier != null ? new InstanceBindingImpl<>(source, classifier, instance) : new InstanceBindingImpl<>(source, classifierType, instance);
101 } else if (providerType != null) {
102 return classifier != null ? new ProviderTypeBindingImpl<>(source, providerType, classifier, singleton) : new ProviderTypeBindingImpl<>(source, providerType, classifierType, singleton);
103 } else if (provider != null) {
104 return classifier != null ? new ProviderBindingImpl<>(source, provider, classifier, singleton) : new ProviderBindingImpl<>(source, provider, classifierType, singleton);
105 } else if (target != null) {
106 return classifier != null ? new TargetBindingImpl<>(source, target, classifier, singleton) : new TargetBindingImpl<>(source, target, classifierType, singleton);
107 }
108
109 return classifier != null ? new TargetBindingImpl<>(source, source, classifier, singleton) : new TargetBindingImpl<>(source, source, classifierType, singleton);
110 }
111
112 @Nonnull
113 @Override
114 public LinkedBindingBuilder<T> withClassifier(@Nonnull Class<? extends Annotation> annotationType) {
115 requireNonNull(annotationType, "Argument 'annotationType' must not be null");
116 AnnotationUtils.requireAnnotation(annotationType, Qualifier.class);
117 this.classifierType = annotationType;
118 return this;
119 }
120
121 @Nonnull
122 @Override
123 public LinkedBindingBuilder<T> withClassifier(@Nonnull Annotation annotation) {
124 requireNonNull(annotation, "Argument 'annotation' must not be null");
125 this.classifier = annotation;
126 withClassifier(annotation.getClass());
127 return this;
128 }
129 }
130
131 private static abstract class AbstractBindingImpl<T> implements Binding<T> {
132 protected final Class<T> source;
133 protected final boolean singleton;
134 protected Annotation classifier;
135 protected Class<? extends Annotation> classifierType;
136
137 protected AbstractBindingImpl(@Nonnull Class<T> source, @Nonnull Annotation classifier, boolean singleton) {
138 this.source = source;
139 this.singleton = singleton;
140 this.classifier = classifier;
141 this.classifierType = classifier.getClass();
142 }
143
144 protected AbstractBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends Annotation> classifierType, boolean singleton) {
145 this.source = source;
146 this.singleton = singleton;
147 this.classifierType = classifierType;
148 }
149
150 @Nonnull
151 @Override
152 public Class<T> getSource() {
153 return source;
154 }
155
156 @Nullable
157 @Override
158 public Class<? extends Annotation> getClassifierType() {
159 return classifierType;
160 }
161
162 @Nullable
163 @Override
164 public Annotation getClassifier() {
165 return classifier;
166 }
167
168 @Override
169 public boolean isSingleton() {
170 return singleton;
171 }
172
173 protected void updateClassifier(Class<?> klass) {
174 if (this.classifier == null) {
175 List<Annotation> qualifiers = harvestQualifiers(klass);
176 if (!qualifiers.isEmpty()) {
177 this.classifier = qualifiers.get(0);
178 }
179 }
180 }
181
182 protected void updateClassifierType(Class<?> klass) {
183 if (this.classifierType == null) {
184 List<Annotation> qualifiers = harvestQualifiers(klass);
185 if (!qualifiers.isEmpty()) {
186 this.classifier = qualifiers.get(0);
187 }
188 }
189 }
190 }
191
192 private static class TargetBindingImpl<T> extends AbstractBindingImpl<T> implements TargetBinding<T> {
193 private final Class<? extends T> target;
194
195 private TargetBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends T> target, @Nonnull Annotation classifier, boolean singleton) {
196 super(source, classifier, singleton);
197 this.target = target;
198 updateClassifier(target);
199 }
200
201 private TargetBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends T> target, @Nonnull Class<? extends Annotation> classifierType, boolean singleton) {
202 super(source, classifierType, singleton);
203 this.target = target;
204 updateClassifierType(target);
205 }
206
207 @Nonnull
208 @Override
209 public Class<? extends T> getTarget() {
210 return target;
211 }
212
213 @Override
214 public String toString() {
215 final StringBuilder sb = new StringBuilder("TargetBinding[");
216 sb.append("source=").append(source.getName());
217 if (classifier != null) {
218 sb.append(", classifier=").append(classifier);
219 } else if (classifierType != null) {
220 sb.append(", classifierType=").append(classifierType.getName());
221 }
222 sb.append(", target=").append(target.getName());
223 sb.append(", singleton=").append(singleton);
224 sb.append(']');
225 return sb.toString();
226 }
227 }
228
229 private static class InstanceBindingImpl<T> extends AbstractBindingImpl<T> implements InstanceBinding<T> {
230 private final T instance;
231
232 protected InstanceBindingImpl(@Nonnull Class<T> source, @Nonnull Annotation classifier, @Nonnull T instance) {
233 super(source, classifier, true);
234 this.instance = instance;
235 updateClassifier(instance.getClass());
236 }
237
238 protected InstanceBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends Annotation> classifierType, @Nonnull T instance) {
239 super(source, classifierType, true);
240 this.instance = instance;
241 updateClassifierType(instance.getClass());
242 }
243
244 @Nonnull
245 @Override
246 public T getInstance() {
247 return instance;
248 }
249
250 @Override
251 public String toString() {
252 final StringBuilder sb = new StringBuilder("InstanceBinding[");
253 sb.append("source=").append(source.getName());
254 if (classifier != null) {
255 sb.append(", classifier=").append(classifier);
256 } else if (classifierType != null) {
257 sb.append(", classifierType=").append(classifierType.getName());
258 }
259 sb.append(", instance=").append(instance);
260 sb.append(", singleton=").append(singleton);
261 sb.append(']');
262 return sb.toString();
263 }
264 }
265
266 private static class ProviderBindingImpl<T> extends AbstractBindingImpl<T> implements ProviderBinding<T> {
267 private final Provider<T> provider;
268
269 private ProviderBindingImpl(@Nonnull Class<T> source, @Nonnull Provider<T> provider, @Nonnull Annotation classifier, boolean singleton) {
270 super(source, classifier, singleton);
271 this.provider = provider;
272 updateClassifier(provider.getClass());
273 }
274
275
276 private ProviderBindingImpl(@Nonnull Class<T> source, @Nonnull Provider<T> provider, @Nonnull Class<? extends Annotation> classifierType, boolean singleton) {
277 super(source, classifierType, singleton);
278 this.provider = provider;
279 updateClassifierType(provider.getClass());
280 }
281
282 @Nonnull
283 @Override
284 public Provider<T> getProvider() {
285 return provider;
286 }
287
288 @Override
289 public String toString() {
290 final StringBuilder sb = new StringBuilder("ProviderBinding[");
291 sb.append("source=").append(source.getName());
292 if (classifier != null) {
293 sb.append(", classifier=").append(classifier);
294 } else if (classifierType != null) {
295 sb.append(", classifierType=").append(classifierType.getName());
296 }
297 sb.append(", provider=").append(provider);
298 sb.append(", singleton=").append(singleton);
299 sb.append(']');
300 return sb.toString();
301 }
302 }
303
304 private static class ProviderTypeBindingImpl<T> extends AbstractBindingImpl<T> implements ProviderTypeBinding<T> {
305 private final Class<? extends Provider<T>> providerType;
306
307 private ProviderTypeBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends Provider<T>> providerType, @Nonnull Annotation classifier, boolean singleton) {
308 super(source, classifier, singleton);
309 this.providerType = providerType;
310 updateClassifier(providerType);
311 }
312
313
314 private ProviderTypeBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends Provider<T>> providerType, @Nonnull Class<? extends Annotation> classifierType, boolean singleton) {
315 super(source, classifierType, singleton);
316 this.providerType = providerType;
317 updateClassifierType(providerType);
318 }
319
320 @Nonnull
321 @Override
322 public Class<? extends Provider<T>> getProviderType() {
323 return providerType;
324 }
325
326 @Override
327 public String toString() {
328 final StringBuilder sb = new StringBuilder("ProviderTypeBinding[");
329 sb.append("source=").append(source.getName());
330 if (classifier != null) {
331 sb.append(", classifier=").append(classifier);
332 } else if (classifierType != null) {
333 sb.append(", classifierType=").append(classifierType.getName());
334 }
335 sb.append(", providerType=").append(providerType.getName());
336 sb.append(", singleton=").append(singleton);
337 sb.append(']');
338 return sb.toString();
339 }
340 }
341 }
|