View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
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      // endregion
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 }