1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  package org.apache.maven.di.impl;
20  
21  import java.lang.annotation.Annotation;
22  import java.util.*;
23  import java.util.function.Consumer;
24  import java.util.function.Function;
25  import java.util.function.Supplier;
26  import java.util.stream.Collectors;
27  import java.util.stream.Stream;
28  
29  import org.apache.maven.di.Key;
30  
31  import static java.util.stream.Collectors.joining;
32  
33  public abstract class Binding<T> {
34      private final Set<Key<?>> dependencies;
35      private Annotation scope;
36      private int priority;
37      private Key<?> originalKey;
38  
39      protected Binding(Key<? extends T> originalKey, Set<Key<?>> dependencies) {
40          this(originalKey, dependencies, null, 0);
41      }
42  
43      protected Binding(Key<?> originalKey, Set<Key<?>> dependencies, Annotation scope, int priority) {
44          this.originalKey = originalKey;
45          this.dependencies = dependencies;
46          this.scope = scope;
47          this.priority = priority;
48      }
49  
50      public static <T> Binding<T> toInstance(T instance) {
51          return new BindingToInstance<>(instance);
52      }
53  
54      public static <R> Binding<R> to(Key<R> originalKey, TupleConstructorN<R> constructor, Class<?>[] types) {
55          return Binding.to(
56                  originalKey, constructor, Stream.of(types).map(Key::of).toArray(Key<?>[]::new));
57      }
58  
59      public static <R> Binding<R> to(Key<R> originalKey, TupleConstructorN<R> constructor, Key<?>[] dependencies) {
60          return to(originalKey, constructor, dependencies, 0);
61      }
62  
63      public static <R> Binding<R> to(
64              Key<R> originalKey, TupleConstructorN<R> constructor, Key<?>[] dependencies, int priority) {
65          return new BindingToConstructor<>(originalKey, constructor, dependencies, priority);
66      }
67  
68      
69  
70      public Binding<T> scope(Annotation scope) {
71          this.scope = scope;
72          return this;
73      }
74  
75      public Binding<T> prioritize(int priority) {
76          this.priority = priority;
77          return this;
78      }
79  
80      public Binding<T> withKey(Key<?> key) {
81          this.originalKey = key;
82          return this;
83      }
84  
85      public Binding<T> initializeWith(BindingInitializer<T> bindingInitializer) {
86          return new Binding<T>(
87                  this.originalKey,
88                  Stream.of(this.dependencies, bindingInitializer.getDependencies())
89                          .flatMap(Set::stream)
90                          .collect(Collectors.toSet()),
91                  this.scope,
92                  this.priority) {
93              @Override
94              public Supplier<T> compile(Function<Key<?>, Supplier<?>> compiler) {
95                  final Supplier<T> compiledBinding = Binding.this.compile(compiler);
96                  final Consumer<T> consumer = bindingInitializer.compile(compiler);
97                  return () -> {
98                      T instance = compiledBinding.get();
99                      consumer.accept(instance);
100                     return instance;
101                 };
102             }
103 
104             @Override
105             public String toString() {
106                 return Binding.this.toString();
107             }
108         };
109     }
110 
111     public abstract Supplier<T> compile(Function<Key<?>, Supplier<?>> compiler);
112 
113     public Set<Key<?>> getDependencies() {
114         return dependencies;
115     }
116 
117     public Annotation getScope() {
118         return scope;
119     }
120 
121     public String getDisplayString() {
122         return dependencies.stream().map(Key::getDisplayString).collect(joining(", ", "[", "]"));
123     }
124 
125     public Key<?> getOriginalKey() {
126         return originalKey;
127     }
128 
129     public int getPriority() {
130         return priority;
131     }
132 
133     @Override
134     public String toString() {
135         return "Binding" + dependencies.toString();
136     }
137 
138     @FunctionalInterface
139     public interface TupleConstructorN<R> {
140         R create(Object... args);
141     }
142 
143     public static class BindingToInstance<T> extends Binding<T> {
144         final T instance;
145 
146         BindingToInstance(T instance) {
147             super(null, Collections.emptySet());
148             this.instance = instance;
149         }
150 
151         @Override
152         public Supplier<T> compile(Function<Key<?>, Supplier<?>> compiler) {
153             return () -> instance;
154         }
155 
156         @Override
157         public String toString() {
158             return "BindingToInstance[" + instance + "]" + getDependencies();
159         }
160     }
161 
162     public static class BindingToConstructor<T> extends Binding<T> {
163         final TupleConstructorN<T> constructor;
164         final Key<?>[] args;
165 
166         BindingToConstructor(
167                 Key<? extends T> key, TupleConstructorN<T> constructor, Key<?>[] dependencies, int priority) {
168             super(key, new HashSet<>(Arrays.asList(dependencies)), null, priority);
169             this.constructor = constructor;
170             this.args = dependencies;
171         }
172 
173         @Override
174         public Supplier<T> compile(Function<Key<?>, Supplier<?>> compiler) {
175             return () -> {
176                 Object[] args =
177                         Stream.of(this.args).map(compiler).map(Supplier::get).toArray();
178                 return constructor.create(args);
179             };
180         }
181 
182         @Override
183         public String toString() {
184             return "BindingToConstructor[" + constructor + "]" + getDependencies();
185         }
186     }
187 }