1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.ui.framework.ioc;
35
36 import static java.util.stream.Collectors.toMap;
37
38 import info.magnolia.config.NamedDefinition;
39 import info.magnolia.objectfactory.CandidateParameterResolver;
40 import info.magnolia.objectfactory.ComponentProvider;
41 import info.magnolia.objectfactory.ParameterResolver;
42 import info.magnolia.objectfactory.guice.GuiceComponentProvider;
43 import info.magnolia.ui.datasource.WithDatasource;
44 import info.magnolia.ui.framework.datasource.definition.DatasourceDefinition;
45 import info.magnolia.util.Util;
46
47 import java.io.Serializable;
48 import java.util.Arrays;
49 import java.util.HashMap;
50 import java.util.Map;
51 import java.util.Optional;
52 import java.util.function.Function;
53 import java.util.function.Supplier;
54 import java.util.stream.Stream;
55
56 import com.google.inject.Inject;
57 import com.google.inject.Key;
58 import com.vaadin.server.VaadinServlet;
59
60
61
62
63
64
65
66
67
68
69
70
71
72 public class UiContextBoundComponentProvider implements ComponentProvider, Serializable {
73
74 private final transient GuiceComponentProvider parentComponentProvider;
75
76 private final CurrentUiContextReference currentUiContextReference;
77
78 private final UiContextReference uiContextReference;
79
80 @Inject
81 public UiContextBoundComponentProvider(UiContextReference uiContextReference) {
82 this(uiContextReference, (GuiceComponentProvider) VaadinServlet.getCurrent().getServletContext().getAttribute("componentProvider"), CurrentUiContextReference.get());
83 }
84
85 public UiContextBoundComponentProvider(UiContextReference uiContextReference, GuiceComponentProvider parentComponentProvider) {
86 this(uiContextReference, parentComponentProvider, CurrentUiContextReference.get());
87 }
88
89 public UiContextBoundComponentProvider(UiContextReference uiContextReference, GuiceComponentProvider parentComponentProvider, CurrentUiContextReference currentUiContextReference) {
90 this.uiContextReference = uiContextReference;
91 this.parentComponentProvider = parentComponentProvider;
92 this.currentUiContextReference = currentUiContextReference;
93 }
94
95 public UiContextReference getUiContextReference() {
96 return this.uiContextReference;
97 }
98
99 @Override
100 public <T> Class<? extends T> getImplementation(Class<T> type) {
101 return getParent().getImplementation(getClosestMappedType(type));
102 }
103
104 private <T> Key<T> getClosestMappedType(Class<T> type) {
105 return getReachableUiContextReferences()
106 .map(key -> Key.get(type, key.getAnnotation()))
107
108 .filter(key -> getParent().getTypeMappings().containsKey(key))
109 .findFirst()
110
111 .orElseGet(() -> Key.get(type));
112 }
113
114 protected Stream<UiContextReference> getReachableUiContextReferences() {
115 return this.currentUiContextReference.getAvailableContextReferences().stream();
116 }
117
118 @Override
119 public <T> T getSingleton(Class<T> type) {
120 return getParent().getSingleton(type);
121 }
122
123 @Override
124 public <T> T getComponent(Class<T> type) {
125 return provideInCurrentScope(() -> getParent().getComponent(type));
126 }
127
128 @Override
129 public <T> T newInstance(Class<T> type, Object... parameters) {
130 return newInstanceWithParameterResolvers(type, new CandidateParameterResolver(parameters));
131 }
132
133 @Override
134 public <T> T newInstanceWithParameterResolvers(Class<T> type, ParameterResolver... parameters) {
135 return provideInCurrentScope(() -> getParent().newInstanceWithParameterResolvers(getClosestMappedType(type), parameters));
136 }
137
138 @Override
139 public GuiceComponentProvider getParent() {
140 return this.parentComponentProvider;
141 }
142
143 public UiContextBoundComponentProvider inChildContext(String name, Object definition) {
144 Builder builder = builder(name, uiContextReference).withInstances(definition);
145 if (definition instanceof WithDatasource) {
146 Map<Class, Object> instances = new HashMap<>();
147 Optional.ofNullable(((WithDatasource) definition).getDatasource())
148 .ifPresent(datasourceDefinition -> instances.put(DatasourceDefinition.class, datasourceDefinition));
149 builder = builder.withInstances(instances);
150 }
151
152 return builder.build();
153 }
154
155 public UiContextBoundComponentProvider inChildContext(NamedDefinition definition) {
156 return inChildContext(definition.getName(), definition);
157 }
158
159 private <T> T provideInCurrentScope(Supplier<T> provider) {
160 final UiContextReference previousUiContextReference = currentUiContextReference.getUiContextReference();
161 currentUiContextReference.setUiContextReference(this.uiContextReference);
162 try {
163 return provider.get();
164 } finally {
165 currentUiContextReference.setUiContextReference(previousUiContextReference);
166 }
167 }
168
169 public static Builder builder(String name, UiContextReference parentReference) {
170 String id = name;
171 UiContextReference viewContextReference;
172 do {
173 viewContextReference = UiContextReference.ofView(id, parentReference);
174 id = Util.createUniqueName(id);
175 } while (SessionStore.access().getBeanStore(viewContextReference) != null);
176
177 return new Builder().withUiContextReference(viewContextReference);
178 }
179
180 public static class Builder {
181
182 private Builder() {
183 }
184
185 private UiContextReference uiContextReference;
186 private Map<Class, Object> instances = new HashMap<>();
187
188 public Builder withUiContextReference(UiContextReference uiContextReference) {
189 this.uiContextReference = uiContextReference;
190 return this;
191 }
192
193 public Builder withInstances(Object... instances) {
194 this.instances.putAll(Arrays.stream(instances)
195 .collect(toMap(Object::getClass, Function.identity(), (first, second) -> second)));
196 return this;
197 }
198
199 public Builder withInstances(Map<Class, Object> instances) {
200 this.instances.putAll(instances);
201 return this;
202 }
203
204 public UiContextBoundComponentProvider build() {
205 BeanStore beanStore = SessionStore.access().createBeanStore(uiContextReference);
206 instances.forEach(beanStore::put);
207
208 ViewComponentProviderml#ViewComponentProvider">ViewComponentProvider viewComponentProvider = new ViewComponentProvider(uiContextReference);
209 beanStore.put(UiContextBoundComponentProvider.class, viewComponentProvider);
210 beanStore.put(ComponentProvider.class, viewComponentProvider);
211
212 return viewComponentProvider;
213 }
214 }
215 }