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