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.framework.UiFrameworkView;
41 import info.magnolia.ui.framework.ViewContext;
42 import info.magnolia.ui.framework.ViewContextBase;
43 import info.magnolia.ui.framework.ViewContextProxy;
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 ViewContextParameterResolver 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 ViewContextParameterResolver(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 (ViewContext.class.isAssignableFrom(parameterType)) {
113 return createNewContext((Class) parameterType);
114 }
115
116 return UNRESOLVED;
117 }));
118
119 if ((param instanceof ViewContext) && !valueFromCurrentStore.isPresent()) {
120 final ViewContext wrappedViewContext = wrapViewContext((ViewContext) param);
121 beanStore.put(parameterType, wrappedViewContext);
122 return wrappedViewContext;
123 }
124
125 return param;
126 }
127
128 private <T extends ViewContext> T createNewContext(Class<T> contextType) {
129 final T context = new ViewContextProxy().createViewContext(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 .map(parentStore -> parentStore.getClosestInstance(parameterType))
138 .filter(Objects::nonNull)
139 .findFirst()
140 .map(parameter -> parameter instanceof ViewContext ? wrapViewContext((ViewContext) parameter) : parameter);
141 }
142
143 private ViewContext wrapViewContext(ViewContext viewContext) {
144 final ViewContextBase baseViewContext = (ViewContextBase) viewContext;
145 final Map<String, ContextProperty> properties = baseViewContext.properties();
146 final Map<String, ContextProperty> wrappedProperties =
147 properties.entrySet()
148 .stream()
149 .collect(Collectors.toMap(Map.Entry::getKey, entry -> {
150 final ContextProperty<?> contextProperty = entry.getValue();
151 return new LeakagePreventingWrapper<>(contextProperty);
152 }));
153
154 return new ViewContextProxy().createViewContext(baseViewContext.getViewContextType(), wrappedProperties);
155 }
156 }