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 }