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.Arrays;
23 import java.util.Collections;
24 import java.util.Comparator;
25 import java.util.HashSet;
26 import java.util.Set;
27 import java.util.function.Consumer;
28 import java.util.function.Function;
29 import java.util.function.Supplier;
30 import java.util.stream.Collectors;
31 import java.util.stream.Stream;
32
33 import org.apache.maven.di.Key;
34
35 public abstract class Binding<T> {
36 private final Set<Dependency<?>> dependencies;
37 private Annotation scope;
38 private int priority;
39 private Key<?> originalKey;
40
41 protected Binding(Key<? extends T> originalKey, Set<Dependency<?>> dependencies) {
42 this(originalKey, dependencies, null, 0);
43 }
44
45 protected Binding(Key<?> originalKey, Set<Dependency<?>> dependencies, Annotation scope, int priority) {
46 this.originalKey = originalKey;
47 this.dependencies = dependencies;
48 this.scope = scope;
49 this.priority = priority;
50 }
51
52 public static <T> Binding<T> toInstance(T instance) {
53 return new BindingToInstance<>(instance);
54 }
55
56 public static <T> Binding<T> toSupplier(Supplier<T> supplier) {
57 return new BindingToSupplier<>(supplier);
58 }
59
60 public static <R> Binding<R> to(Key<R> originalKey, TupleConstructorN<R> constructor, Class<?>[] types) {
61 return Binding.to(
62 originalKey,
63 constructor,
64 Stream.of(types).map(c -> new Dependency<>(Key.of(c), false)).toArray(Dependency<?>[]::new));
65 }
66
67 public static <R> Binding<R> to(
68 Key<R> originalKey, TupleConstructorN<R> constructor, Dependency<?>[] dependencies) {
69 return to(originalKey, constructor, dependencies, 0);
70 }
71
72 public static <R> Binding<R> to(
73 Key<R> originalKey, TupleConstructorN<R> constructor, Dependency<?>[] dependencies, int priority) {
74 return new BindingToConstructor<>(originalKey, constructor, dependencies, priority);
75 }
76
77
78
79 public Binding<T> scope(Annotation scope) {
80 this.scope = scope;
81 return this;
82 }
83
84 public Binding<T> prioritize(int priority) {
85 this.priority = priority;
86 return this;
87 }
88
89 public Binding<T> withKey(Key<?> key) {
90 this.originalKey = key;
91 return this;
92 }
93
94 public Binding<T> initializeWith(BindingInitializer<T> bindingInitializer) {
95 return new Binding<T>(
96 this.originalKey,
97 Stream.of(this.dependencies, bindingInitializer.getDependencies())
98 .flatMap(Set::stream)
99 .collect(Collectors.toSet()),
100 this.scope,
101 this.priority) {
102 @Override
103 public Supplier<T> compile(Function<Dependency<?>, Supplier<?>> compiler) {
104 final Supplier<T> compiledBinding = Binding.this.compile(compiler);
105 final Consumer<T> consumer = bindingInitializer.compile(compiler);
106 return () -> {
107 try {
108 T instance = compiledBinding.get();
109 consumer.accept(instance);
110 return instance;
111 } catch (DIException e) {
112 throw new DIException("Error while initializing binding " + Binding.this, e);
113 }
114 };
115 }
116
117 @Override
118 public String toString() {
119 return Binding.this.toString();
120 }
121 };
122 }
123
124 public abstract Supplier<T> compile(Function<Dependency<?>, Supplier<?>> compiler);
125
126 public Set<Dependency<?>> getDependencies() {
127 return dependencies;
128 }
129
130 public Annotation getScope() {
131 return scope;
132 }
133
134 public Key<?> getOriginalKey() {
135 return originalKey;
136 }
137
138 public int getPriority() {
139 return priority;
140 }
141
142 @Override
143 public String toString() {
144 return "Binding" + dependencies.toString();
145 }
146
147 @FunctionalInterface
148 public interface TupleConstructorN<R> {
149 R create(Object... args);
150 }
151
152 public static Comparator<Binding<?>> getPriorityComparator() {
153 return Comparator.<Binding<?>>comparingInt(Binding::getPriority).reversed();
154 }
155
156 public static class BindingToInstance<T> extends Binding<T> {
157 final T instance;
158
159 public BindingToInstance(T instance) {
160 super(null, Collections.emptySet());
161 this.instance = instance;
162 }
163
164 @Override
165 public Supplier<T> compile(Function<Dependency<?>, Supplier<?>> compiler) {
166 return () -> instance;
167 }
168
169 @Override
170 public String toString() {
171 return "BindingToInstance[" + instance + "]" + getDependencies();
172 }
173 }
174
175 public static class BindingToSupplier<T> extends Binding<T> {
176 final Supplier<T> supplier;
177
178 public BindingToSupplier(Supplier<T> supplier) {
179 super(null, Collections.emptySet());
180 this.supplier = supplier;
181 }
182
183 @Override
184 public Supplier<T> compile(Function<Dependency<?>, Supplier<?>> compiler) {
185 return supplier;
186 }
187
188 @Override
189 public String toString() {
190 return "BindingToSupplier[" + supplier + "]" + getDependencies();
191 }
192 }
193
194 public static class BindingToConstructor<T> extends Binding<T> {
195 final TupleConstructorN<T> constructor;
196 final Dependency<?>[] args;
197
198 BindingToConstructor(
199 Key<? extends T> key, TupleConstructorN<T> constructor, Dependency<?>[] dependencies, int priority) {
200 super(key, new HashSet<>(Arrays.asList(dependencies)), null, priority);
201 this.constructor = constructor;
202 this.args = dependencies;
203 }
204
205 @Override
206 public Supplier<T> compile(Function<Dependency<?>, Supplier<?>> compiler) {
207 return () -> {
208 Object[] args =
209 Stream.of(this.args).map(compiler).map(Supplier::get).toArray();
210 return constructor.create(args);
211 };
212 }
213
214 @Override
215 public String toString() {
216 return "BindingToConstructor[" + getOriginalKey() + "]" + getDependencies();
217 }
218 }
219 }