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.*;
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      // endregion
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 }