1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.impl.di;
20
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.LinkedList;
24 import java.util.Map;
25 import java.util.function.Supplier;
26
27 import org.apache.maven.api.annotations.Nonnull;
28 import org.apache.maven.di.Key;
29 import org.apache.maven.di.Scope;
30 import org.apache.maven.di.impl.DIException;
31
32
33
34
35 public class MojoExecutionScope implements Scope {
36
37 protected static final class ScopeState {
38 private final Map<Key<?>, Supplier<?>> seeded = new HashMap<>();
39
40 private final Map<Key<?>, Object> provided = new HashMap<>();
41
42 public <T> void seed(Class<T> clazz, Supplier<T> value) {
43 seeded.put(Key.of(clazz), value);
44 }
45
46 public Collection<Object> provided() {
47 return provided.values();
48 }
49 }
50
51 private final ThreadLocal<LinkedList<ScopeState>> values = new ThreadLocal<>();
52
53 public MojoExecutionScope() {}
54
55 public static <T> Supplier<T> seededKeySupplier(Class<? extends T> clazz) {
56 return () -> {
57 throw new IllegalStateException(
58 "No instance of " + clazz.getName() + " is bound to the mojo execution scope.");
59 };
60 }
61
62 public void enter() {
63 LinkedList<ScopeState> stack = values.get();
64 if (stack == null) {
65 stack = new LinkedList<>();
66 values.set(stack);
67 }
68 stack.addFirst(new ScopeState());
69 }
70
71 protected ScopeState getScopeState() {
72 LinkedList<ScopeState> stack = values.get();
73 if (stack == null || stack.isEmpty()) {
74 throw new IllegalStateException();
75 }
76 return stack.getFirst();
77 }
78
79 public void exit() {
80 final LinkedList<ScopeState> stack = values.get();
81 if (stack == null || stack.isEmpty()) {
82 throw new IllegalStateException();
83 }
84 stack.removeFirst();
85 if (stack.isEmpty()) {
86 values.remove();
87 }
88 }
89
90 public <T> void seed(Class<T> clazz, Supplier<T> value) {
91 getScopeState().seed(clazz, value);
92 }
93
94 public <T> void seed(Class<T> clazz, final T value) {
95 seed(clazz, (Supplier<T>) () -> value);
96 }
97
98 @SuppressWarnings("unchecked")
99 @Nonnull
100 public <T> Supplier<T> scope(@Nonnull Key<T> key, @Nonnull Supplier<T> unscoped) {
101 return () -> {
102 LinkedList<ScopeState> stack = values.get();
103 if (stack == null || stack.isEmpty()) {
104 throw new DIException("Cannot access " + key + " outside of a scoping block");
105 }
106
107 ScopeState state = stack.getFirst();
108
109 Supplier<?> seeded = state.seeded.get(key);
110
111 if (seeded != null) {
112 return (T) seeded.get();
113 }
114
115 T provided = (T) state.provided.get(key);
116 if (provided == null && unscoped != null) {
117 provided = unscoped.get();
118 state.provided.put(key, provided);
119 }
120
121 return provided;
122 };
123 }
124 }