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