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