001 /* 
002  * Copyright 2008-2017 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     private Bindings() { 
041         // prevent instantiation 
042     } 
043  
044     public static <T> AnnotatedBindingBuilder<T> bind(@Nonnull Class<T> clazz) { 
045         requireNonNull(clazz, "Argument 'class' must not be null"); 
046         return new AnnotatedBindingBuilderImpl<>(clazz); 
047     } 
048  
049     private abstract static class SingletonBindingBuilderImpl<T> implements SingletonBindingBuilder<T> { 
050         protected boolean singleton; 
051  
052         @Override 
053         public void asSingleton() { 
054             singleton = true; 
055         } 
056     } 
057  
058     private abstract static class LinkedBindingBuilderImpl<T> extends SingletonBindingBuilderImpl<T> implements LinkedBindingBuilder<T> { 
059         protected Class<? extends T> target; 
060         protected T instance; 
061         protected Provider<T> provider; 
062         protected Class<? extends Provider<T>> providerType; 
063  
064         @Nonnull 
065         @Override 
066         public SingletonBindingBuilder<T> to(@Nonnull Class<? extends T> target) { 
067             this.target = requireNonNull(target, "Argument 'target' must not be null"); 
068             return this; 
069         } 
070  
071         @Override 
072         public void toInstance(@Nonnull T instance) { 
073             this.instance = requireNonNull(instance, "Argument 'instance' must not be null"); 
074         } 
075  
076         @Nonnull 
077         @Override 
078         public SingletonBindingBuilder<T> toProvider(@Nonnull Provider<T> provider) { 
079             this.provider = requireNonNull(provider, "Argument 'provider' must not be null"); 
080             return this; 
081         } 
082  
083         @Nonnull 
084         @Override 
085         public SingletonBindingBuilder<T> toProvider(@Nonnull Class<? extends Provider<T>> providerType) { 
086             this.providerType = requireNonNull(providerType, "Argument 'providerType' must not be null"); 
087             return this; 
088         } 
089     } 
090  
091     private static class AnnotatedBindingBuilderImpl<T> extends LinkedBindingBuilderImpl<T> implements AnnotatedBindingBuilder<T> { 
092         private final Class<T> source; 
093         private Annotation classifier; 
094         private Class<? extends Annotation> classifierType; 
095  
096         private AnnotatedBindingBuilderImpl(@Nonnull Class<T> source) { 
097             this.source = requireNonNull(source, "Argument 'source' must not be null"); 
098         } 
099  
100         @Nonnull 
101         @Override 
102         public Binding<T> getBinding() { 
103             if (instance != null) { 
104                 return classifier != null ? new InstanceBindingImpl<>(source, classifier, instance) : new InstanceBindingImpl<>(source, classifierType, instance); 
105             } else if (providerType != null) { 
106                 return classifier != null ? new ProviderTypeBindingImpl<>(source, providerType, classifier, singleton) : new ProviderTypeBindingImpl<>(source, providerType, classifierType, singleton); 
107             } else if (provider != null) { 
108                 return classifier != null ? new ProviderBindingImpl<>(source, provider, classifier, singleton) : new ProviderBindingImpl<>(source, provider, classifierType, singleton); 
109             } else if (target != null) { 
110                 return classifier != null ? new TargetBindingImpl<>(source, target, classifier, singleton) : new TargetBindingImpl<>(source, target, classifierType, singleton); 
111             } 
112  
113             return classifier != null ? new TargetBindingImpl<>(source, source, classifier, singleton) : new TargetBindingImpl<>(source, source, classifierType, singleton); 
114         } 
115  
116         @Nonnull 
117         @Override 
118         public LinkedBindingBuilder<T> withClassifier(@Nonnull Class<? extends Annotation> annotationType) { 
119             requireNonNull(annotationType, "Argument 'annotationType' must not be null"); 
120             AnnotationUtils.requireAnnotation(annotationType, Qualifier.class); 
121             this.classifierType = annotationType; 
122             return this; 
123         } 
124  
125         @Nonnull 
126         @Override 
127         public LinkedBindingBuilder<T> withClassifier(@Nonnull Annotation annotation) { 
128             requireNonNull(annotation, "Argument 'annotation' must not be null"); 
129             this.classifier = annotation; 
130             withClassifier(annotation.getClass()); 
131             return this; 
132         } 
133     } 
134  
135     private abstract static class AbstractBindingImpl<T> implements Binding<T> { 
136         protected final Class<T> source; 
137         protected final boolean singleton; 
138         protected Annotation classifier; 
139         protected Class<? extends Annotation> classifierType; 
140  
141         protected AbstractBindingImpl(@Nonnull Class<T> source, @Nonnull Annotation classifier, boolean singleton) { 
142             this.source = source; 
143             this.singleton = singleton; 
144             this.classifier = classifier; 
145             this.classifierType = classifier.getClass(); 
146         } 
147  
148         protected AbstractBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends Annotation> classifierType, boolean singleton) { 
149             this.source = source; 
150             this.singleton = singleton; 
151             this.classifierType = classifierType; 
152         } 
153  
154         @Nonnull 
155         @Override 
156         public Class<T> getSource() { 
157             return source; 
158         } 
159  
160         @Nullable 
161         @Override 
162         public Class<? extends Annotation> getClassifierType() { 
163             return classifierType; 
164         } 
165  
166         @Nullable 
167         @Override 
168         public Annotation getClassifier() { 
169             return classifier; 
170         } 
171  
172         @Override 
173         public boolean isSingleton() { 
174             return singleton; 
175         } 
176  
177         protected void updateClassifier(Class<?> klass) { 
178             if (this.classifier == null) { 
179                 List<Annotation> qualifiers = harvestQualifiers(klass); 
180                 if (!qualifiers.isEmpty()) { 
181                     this.classifier = qualifiers.get(0); 
182                 } 
183             } 
184         } 
185  
186         protected void updateClassifierType(Class<?> klass) { 
187             if (this.classifierType == null) { 
188                 List<Annotation> qualifiers = harvestQualifiers(klass); 
189                 if (!qualifiers.isEmpty()) { 
190                     this.classifier = qualifiers.get(0); 
191                 } 
192             } 
193         } 
194     } 
195  
196     private static class TargetBindingImpl<T> extends AbstractBindingImpl<T> implements TargetBinding<T> { 
197         private final Class<? extends T> target; 
198  
199         private TargetBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends T> target, @Nonnull Annotation classifier, boolean singleton) { 
200             super(source, classifier, singleton); 
201             this.target = target; 
202             updateClassifier(target); 
203         } 
204  
205         private TargetBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends T> target, @Nonnull Class<? extends Annotation> classifierType, boolean singleton) { 
206             super(source, classifierType, singleton); 
207             this.target = target; 
208             updateClassifierType(target); 
209         } 
210  
211         @Nonnull 
212         @Override 
213         public Class<? extends T> getTarget() { 
214             return target; 
215         } 
216  
217         @Override 
218         public String toString() { 
219             final StringBuilder sb = new StringBuilder("TargetBinding["); 
220             sb.append("source=").append(source.getName()); 
221             if (classifier != null) { 
222                 sb.append(", classifier=").append(classifier); 
223             } else if (classifierType != null) { 
224                 sb.append(", classifierType=").append(classifierType.getName()); 
225             } 
226             sb.append(", target=").append(target.getName()); 
227             sb.append(", singleton=").append(singleton); 
228             sb.append(']'); 
229             return sb.toString(); 
230         } 
231     } 
232  
233     private static class InstanceBindingImpl<T> extends AbstractBindingImpl<T> implements InstanceBinding<T> { 
234         private final T instance; 
235  
236         protected InstanceBindingImpl(@Nonnull Class<T> source, @Nonnull Annotation classifier, @Nonnull T instance) { 
237             super(source, classifier, true); 
238             this.instance = instance; 
239             updateClassifier(instance.getClass()); 
240         } 
241  
242         protected InstanceBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends Annotation> classifierType, @Nonnull T instance) { 
243             super(source, classifierType, true); 
244             this.instance = instance; 
245             updateClassifierType(instance.getClass()); 
246         } 
247  
248         @Nonnull 
249         @Override 
250         public T getInstance() { 
251             return instance; 
252         } 
253  
254         @Override 
255         public String toString() { 
256             final StringBuilder sb = new StringBuilder("InstanceBinding["); 
257             sb.append("source=").append(source.getName()); 
258             if (classifier != null) { 
259                 sb.append(", classifier=").append(classifier); 
260             } else if (classifierType != null) { 
261                 sb.append(", classifierType=").append(classifierType.getName()); 
262             } 
263             sb.append(", instance=").append(instance); 
264             sb.append(", singleton=").append(singleton); 
265             sb.append(']'); 
266             return sb.toString(); 
267         } 
268     } 
269  
270     private static class ProviderBindingImpl<T> extends AbstractBindingImpl<T> implements ProviderBinding<T> { 
271         private final Provider<T> provider; 
272  
273         private ProviderBindingImpl(@Nonnull Class<T> source, @Nonnull Provider<T> provider, @Nonnull Annotation classifier, boolean singleton) { 
274             super(source, classifier, singleton); 
275             this.provider = provider; 
276             updateClassifier(provider.getClass()); 
277         } 
278  
279  
280         private ProviderBindingImpl(@Nonnull Class<T> source, @Nonnull Provider<T> provider, @Nonnull Class<? extends Annotation> classifierType, boolean singleton) { 
281             super(source, classifierType, singleton); 
282             this.provider = provider; 
283             updateClassifierType(provider.getClass()); 
284         } 
285  
286         @Nonnull 
287         @Override 
288         public Provider<T> getProvider() { 
289             return provider; 
290         } 
291  
292         @Override 
293         public String toString() { 
294             final StringBuilder sb = new StringBuilder("ProviderBinding["); 
295             sb.append("source=").append(source.getName()); 
296             if (classifier != null) { 
297                 sb.append(", classifier=").append(classifier); 
298             } else if (classifierType != null) { 
299                 sb.append(", classifierType=").append(classifierType.getName()); 
300             } 
301             sb.append(", provider=").append(provider); 
302             sb.append(", singleton=").append(singleton); 
303             sb.append(']'); 
304             return sb.toString(); 
305         } 
306     } 
307  
308     private static class ProviderTypeBindingImpl<T> extends AbstractBindingImpl<T> implements ProviderTypeBinding<T> { 
309         private final Class<? extends Provider<T>> providerType; 
310  
311         private ProviderTypeBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends Provider<T>> providerType, @Nonnull Annotation classifier, boolean singleton) { 
312             super(source, classifier, singleton); 
313             this.providerType = providerType; 
314             updateClassifier(providerType); 
315         } 
316  
317  
318         private ProviderTypeBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends Provider<T>> providerType, @Nonnull Class<? extends Annotation> classifierType, boolean singleton) { 
319             super(source, classifierType, singleton); 
320             this.providerType = providerType; 
321             updateClassifierType(providerType); 
322         } 
323  
324         @Nonnull 
325         @Override 
326         public Class<? extends Provider<T>> getProviderType() { 
327             return providerType; 
328         } 
329  
330         @Override 
331         public String toString() { 
332             final StringBuilder sb = new StringBuilder("ProviderTypeBinding["); 
333             sb.append("source=").append(source.getName()); 
334             if (classifier != null) { 
335                 sb.append(", classifier=").append(classifier); 
336             } else if (classifierType != null) { 
337                 sb.append(", classifierType=").append(classifierType.getName()); 
338             } 
339             sb.append(", providerType=").append(providerType.getName()); 
340             sb.append(", singleton=").append(singleton); 
341             sb.append(']'); 
342             return sb.toString(); 
343         } 
344     } 
345 }
    
    |