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 info.magnolia.objectfactory.ParameterInfo;
37 import info.magnolia.objectfactory.ParameterResolver;
38 import info.magnolia.ui.framework.ContextProperty;
39 import info.magnolia.ui.framework.LeakagePreventingWrapper;
40 import info.magnolia.ui.UIComponent;
41 import info.magnolia.ui.framework.UiComponentContext;
42 import info.magnolia.ui.framework.UiComponentContextBase;
43 import info.magnolia.ui.framework.UiComponentContextProxy;
44
45 import java.lang.annotation.Annotation;
46 import java.util.Arrays;
47 import java.util.Map;
48 import java.util.Objects;
49 import java.util.Optional;
50 import java.util.stream.Collectors;
51
52 import javax.inject.Named;
53 import javax.inject.Provider;
54
55 import com.google.inject.BindingAnnotation;
56
57
58
59
60
61
62
63
64
65
66
67
68
69 class UiComponentContextParameterResolver implements ParameterResolver {
70
71 private final static Class[] BLACK_LIST = new Class[] { Provider.class, com.google.inject.Provider.class };
72
73 private final UiContextReference uiContextReference;
74
75 UiComponentContextParameterResolver(UiContextReference uiContextReference) {
76 this.uiContextReference = uiContextReference;
77 }
78
79 @Override
80 @SuppressWarnings("unchecked")
81 public Object resolveParameter(ParameterInfo parameter) {
82
83
84
85 if (Arrays.stream(parameter.getParameterAnnotations()).anyMatch(this::isIocRelatedAnnotation)) {
86 return UNRESOLVED;
87 }
88
89 final Class<?> parameterType = parameter.getParameterType();
90
91
92
93
94
95 boolean isBlackListed = Arrays.stream(BLACK_LIST).anyMatch(blackListedType -> blackListedType.isAssignableFrom(parameterType));
96 if (isBlackListed) {
97 return ParameterResolver.UNRESOLVED;
98 }
99
100 return lookup(parameterType);
101 }
102
103 private boolean isIocRelatedAnnotation(Annotation annotation) {
104 return annotation instanceof Named || Arrays.stream(annotation.annotationType().getAnnotations()).anyMatch(BindingAnnotation.class::isInstance);
105 }
106
107 private Object lookup(Class<?> parameterType) {
108 final BeanStore beanStore = SessionStore.access().getBeanStore(uiContextReference);
109 final Optional<Object> valueFromCurrentStore = Optional.ofNullable(beanStore.getClosestInstance(parameterType));
110
111 final Object param = valueFromCurrentStore.orElseGet(() -> resolveInstanceInParentBeanStores(parameterType).orElseGet(() -> {
112 if (UiComponentContext.class.isAssignableFrom(parameterType)) {
113 return createNewContext((Class) parameterType);
114 }
115
116 return UNRESOLVED;
117 }));
118
119 if ((param instanceof UiComponentContext) && !valueFromCurrentStore.isPresent()) {
120 final UiComponentContextiComponentContext.html#UiComponentContext">UiComponentContext wrappedContext = wrapUiComponentContext((UiComponentContext) param);
121 beanStore.put(parameterType, wrappedContext);
122 return wrappedContext;
123 }
124
125 return param;
126 }
127
128 private <T extends UiComponentContext> T createNewContext(Class<T> contextType) {
129 final T context = new UiComponentContextProxy().createUiComponentContext(contextType);
130 SessionStore.access().getBeanStore(uiContextReference).put(contextType, context);
131 return context;
132 }
133
134 private Optional<Object> resolveInstanceInParentBeanStores(Class<?> parameterType) {
135 return uiContextReference.getParentReferences().stream()
136 .map(parentRef -> SessionStore.access().getBeanStore(parentRef))
137 .filter(Objects::nonNull)
138 .map(parentStore -> parentStore.getClosestInstance(parameterType))
139 .filter(Objects::nonNull)
140 .findFirst()
141 .map(parameter -> parameter instanceof UiComponentContext/ui/framework/UiComponentContext.html#UiComponentContext">UiComponentContext ? wrapUiComponentContext((UiComponentContext) parameter) : parameter);
142 }
143
144 private UiComponentContextlia/ui/framework/UiComponentContext.html#UiComponentContext">UiComponentContext wrapUiComponentContext(UiComponentContext uiComponentContext) {
145 final UiComponentContextBaseagnolia/ui/framework/UiComponentContextBase.html#UiComponentContextBase">UiComponentContextBase baseContext = (UiComponentContextBase) uiComponentContext;
146 final Map<String, ContextProperty> properties = baseContext.properties();
147 final Map<String, ContextProperty> wrappedProperties =
148 properties.entrySet()
149 .stream()
150 .collect(Collectors.toMap(Map.Entry::getKey, entry -> {
151 final ContextProperty<?> contextProperty = entry.getValue();
152 return new LeakagePreventingWrapper<>(contextProperty);
153 }));
154
155 return new UiComponentContextProxy().createUiComponentContext(baseContext.getUiComponentContextType(), wrappedProperties);
156 }
157 }