| 
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);
 336             sb.append(", singleton=").append(singleton);
 337             sb.append(']');
 338             return sb.toString();
 339         }
 340     }
 341 }
 |