|
20 | 20 | package com.adobe.acs.commons.wcm.properties.shared.impl;
|
21 | 21 |
|
22 | 22 | import com.adobe.acs.commons.wcm.properties.shared.SharedComponentProperties;
|
23 |
| -import org.apache.felix.scr.annotations.Activate; |
24 | 23 | import org.apache.felix.scr.annotations.Component;
|
25 | 24 | import org.apache.felix.scr.annotations.Reference;
|
26 | 25 | import org.apache.felix.scr.annotations.ReferenceCardinality;
|
|
29 | 28 | import org.apache.sling.api.SlingHttpServletRequest;
|
30 | 29 | import org.apache.sling.api.resource.Resource;
|
31 | 30 | import org.apache.sling.api.resource.ValueMap;
|
| 31 | +import org.apache.sling.api.scripting.LazyBindings; |
32 | 32 | import org.apache.sling.api.scripting.SlingBindings;
|
33 | 33 | import org.apache.sling.scripting.api.BindingsValuesProvider;
|
34 | 34 | import org.slf4j.Logger;
|
35 | 35 | import org.slf4j.LoggerFactory;
|
36 | 36 |
|
37 | 37 | import javax.script.Bindings;
|
38 |
| -import java.lang.reflect.InvocationHandler; |
39 |
| -import java.lang.reflect.Method; |
40 |
| -import java.lang.reflect.Proxy; |
41 | 38 | import java.util.Optional;
|
42 | 39 | import java.util.function.Supplier;
|
43 |
| -import java.util.stream.Stream; |
44 | 40 |
|
45 | 41 | /**
|
46 | 42 | * Bindings Values Provider that adds bindings for globalProperties,
|
|
62 | 58 | public class SharedComponentPropertiesBindingsValuesProvider implements BindingsValuesProvider {
|
63 | 59 | private static final Logger log = LoggerFactory.getLogger(SharedComponentPropertiesBindingsValuesProvider.class);
|
64 | 60 |
|
65 |
| - /** |
66 |
| - * The LazyBindings class, and its Supplier child interface, are introduced in org.apache.sling.api version 2.22.0, |
67 |
| - * which is first included in AEM 6.5 SP7. |
68 |
| - */ |
69 |
| - protected static final String FQDN_LAZY_BINDINGS = "org.apache.sling.api.scripting.LazyBindings"; |
70 |
| - protected static final String SUPPLIER_PROXY_LABEL = "ACS AEM Commons SCP BVP reflective Proxy for LazyBindings.Supplier"; |
71 |
| - |
72 | 61 | /**
|
73 | 62 | * Bind if available, check for null when reading.
|
74 | 63 | */
|
75 | 64 | @Reference(policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL_UNARY)
|
76 | 65 | SharedComponentProperties sharedComponentProperties;
|
77 | 66 |
|
78 |
| - /** |
79 |
| - * Added for pre-6.5.7 support for LazyBindings. This holds the LazyBindings interface |
80 |
| - * if it is discovered on activation, and is used to check if the {@link #addBindings(Bindings)} param |
81 |
| - * is an instance of LazyBindings. This hack is necessary until this bundle can drop support for |
82 |
| - * AEM versions prior to 6.5.7, at which point this variable can be removed, and the {@link #isLazy(Bindings)} |
83 |
| - * method can be simplified to return {@code bindings instanceof LazyBindings}. |
84 |
| - */ |
85 |
| - private Class<? extends Bindings> lazyBindingsType; |
86 |
| - |
87 |
| - /** |
88 |
| - * Added for pre-6.5.7 support for LazyBindings. This holds the LazyBindings.Supplier interface |
89 |
| - * if it is discovered on activation, and is used to create reflection Proxy instances as a hack |
90 |
| - * until this bundle can drop support for AEM versions prior to 6.5.7, at which point this variable |
91 |
| - * can be removed, and the {@link #wrapSupplier(Supplier)} method can be simplified to accept a |
92 |
| - * LazyBindings.Supplier instead of a java.util.function.Supplier and return it (for matching a |
93 |
| - * lambda expression passed at the call site), or to simply return a lambda that calls the get() |
94 |
| - * method on the java.util.function.Supplier argument. |
95 |
| - */ |
96 |
| - private Class<? extends Supplier> supplierType; |
97 |
| - |
98 |
| - /** |
99 |
| - * This variable only exists to facilitate testing for pre-6.5.7 LazyBindings support, so that a non-classpath |
100 |
| - * class loader can be injected, to provide the LazyBindings class. |
101 |
| - */ |
102 |
| - private ClassLoader lazyBindingsClassLoader = SlingBindings.class.getClassLoader(); |
103 |
| - |
104 |
| - /** |
105 |
| - * Called by the unit test to inject a URL class loader that provides a LazyBindings instance |
106 |
| - * at {@link #FQDN_LAZY_BINDINGS}. |
107 |
| - * |
108 |
| - * @param classLoader a new class loader |
109 |
| - * @return the old class loader |
110 |
| - */ |
111 |
| - protected ClassLoader swapLazyBindingsClassLoaderForTesting(ClassLoader classLoader) { |
112 |
| - if (classLoader != null) { |
113 |
| - ClassLoader oldClassLoader = this.lazyBindingsClassLoader; |
114 |
| - this.lazyBindingsClassLoader = classLoader; |
115 |
| - return oldClassLoader; |
116 |
| - } |
117 |
| - return null; |
118 |
| - } |
119 |
| - |
120 |
| - /** |
121 |
| - * Return the resolved lazyBindingsType for testing. |
122 |
| - * |
123 |
| - * @return the lazyBindingsType |
124 |
| - */ |
125 |
| - protected Class<? extends Bindings> getLazyBindingsType() { |
126 |
| - return this.lazyBindingsType; |
127 |
| - } |
128 |
| - |
129 |
| - /** |
130 |
| - * Return the resolved supplierType for testing. |
131 |
| - * |
132 |
| - * @return the supplierType |
133 |
| - */ |
134 |
| - protected Class<? extends Supplier> getSupplierType() { |
135 |
| - return this.supplierType; |
136 |
| - } |
137 |
| - |
138 | 67 | /**
|
139 | 68 | * This method ensures that the provided supplier is appropriately typed for insertion into a SlingBindings
|
140 | 69 | * object. It primarily facilitates lambda type inference (i.e., {@code wrapSupplier(() -> something)} forces
|
141 |
| - * inference to the functional interface type of the method parameter). And so long as pre-6.5.7 AEMs are supported, |
142 |
| - * this method is also responsible for constructing the {@link Proxy} instance when LazyBindings is present at |
143 |
| - * runtime, and for immediately returning {@code Supplier.get()} when it is not present. |
144 |
| - * After support for pre-6.5.7 AEMs is dropped, the method return type can be changed from {@code Object} to |
145 |
| - * {@code <T> LazyBindings.Supplier<T>} to fully support lazy injection. |
| 70 | + * inference to the functional interface type of the method parameter). |
146 | 71 | *
|
147 | 72 | * @param supplier the provided supplier
|
148 |
| - * @return the Supplier as a LazyBindings.Supplier if supported, or the value of the provided supplier if not |
149 |
| - */ |
150 |
| - protected Object wrapSupplier(final Supplier<?> supplier) { |
151 |
| - if (this.supplierType != null) { |
152 |
| - return Proxy.newProxyInstance(lazyBindingsClassLoader, new Class[]{this.supplierType}, |
153 |
| - new SupplierWrapper(supplier)); |
154 |
| - } |
155 |
| - return supplier.get(); |
156 |
| - } |
157 |
| - |
158 |
| - /** |
159 |
| - * The only purpose of this class is to drive the pre-6.5.7 reflection-based Proxy instance returned |
160 |
| - * by {@link #wrapSupplier(Supplier)}. |
161 |
| - */ |
162 |
| - protected static class SupplierWrapper implements InvocationHandler { |
163 |
| - private final Supplier<?> wrapped; |
164 |
| - |
165 |
| - public SupplierWrapper(final Supplier<?> supplier) { |
166 |
| - this.wrapped = supplier; |
167 |
| - } |
168 |
| - |
169 |
| - @Override |
170 |
| - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
171 |
| - // we are implementing a @FunctionalInterface, so don't get carried away with implementing |
172 |
| - // Object methods. |
173 |
| - if ("get".equals(method.getName())) { |
174 |
| - return wrapped.get(); |
175 |
| - } else if ("toString".equals(method.getName())) { |
176 |
| - // return this marker string for visibility in debugging tools. Otherwise, |
177 |
| - // the default toString is "\"null\"", which is confusing |
178 |
| - return SUPPLIER_PROXY_LABEL; |
179 |
| - } |
180 |
| - return method.getDefaultValue(); |
181 |
| - } |
182 |
| - } |
183 |
| - |
184 |
| - /** |
185 |
| - * The purpose of this activate method is to determine if we are running in a 6.5.7+ AEM environment |
186 |
| - * without having to explicitly require {@code org.apache.sling.api.scripting} package version 2.5.0. |
187 |
| - */ |
188 |
| - @Activate |
189 |
| - protected void activate() { |
190 |
| - // use SlingBindings class loader to check for LazyBindings class, |
191 |
| - // to minimize risk involved with using reflection. |
192 |
| - try { |
193 |
| - this.checkAndSetLazyBindingsType(lazyBindingsClassLoader.loadClass(FQDN_LAZY_BINDINGS)); |
194 |
| - } catch (ReflectiveOperationException cnfe) { |
195 |
| - log.info("LazyBindings not found, will resort to injecting immediate Bindings values", cnfe); |
196 |
| - } |
197 |
| - } |
198 |
| - |
199 |
| - /** |
200 |
| - * Check that the provided {@code lazyBindingsType} implements {@link Bindings} and defines an enclosed marker |
201 |
| - * interface named {@code Supplier} that extends {@link Supplier}, and if so, set {@code this.lazyBindingsType} and |
202 |
| - * {@code this.supplierType}. Otherwise, set both to {@code null}. |
| 73 | + * @return the Supplier as a LazyBindings.Supplier |
203 | 74 | */
|
204 |
| - @SuppressWarnings({"squid:S1872", "unchecked"}) |
205 |
| - protected void checkAndSetLazyBindingsType(final Class<?> lazyBindingsType) { |
206 |
| - if (lazyBindingsType != null && Bindings.class.isAssignableFrom(lazyBindingsType)) { |
207 |
| - this.supplierType = (Class<? extends Supplier>) Stream.of(lazyBindingsType.getDeclaredClasses()) |
208 |
| - .filter(clazz -> Supplier.class.getSimpleName().equals(clazz.getSimpleName()) |
209 |
| - && Supplier.class.isAssignableFrom(clazz)).findFirst().orElse(null); |
210 |
| - this.lazyBindingsType = (Class<? extends Bindings>) lazyBindingsType; |
211 |
| - } else { |
212 |
| - log.info("Supplier interface not declared by lazyBindingsType: {}, will resort to immediate Bindings values", |
213 |
| - lazyBindingsType); |
214 |
| - this.supplierType = null; |
215 |
| - this.lazyBindingsType = null; |
216 |
| - } |
| 75 | + protected LazyBindings.Supplier wrapSupplier(final Supplier<?> supplier) { |
| 76 | + return () -> supplier != null ? supplier.get() : null; |
217 | 77 | }
|
218 | 78 |
|
219 | 79 | /**
|
220 |
| - * Check if provided {@code bindings} implements LazyBindings. |
| 80 | + * Check if provided {@code bindings} is an instance of {@link LazyBindings}. |
221 | 81 | *
|
222 | 82 | * @param bindings the parameter from {@link #addBindings(Bindings)}
|
223 | 83 | * @return true if bindings implements LazyBindings
|
224 | 84 | */
|
225 | 85 | private boolean isLazy(Bindings bindings) {
|
226 |
| - return Optional.ofNullable(this.lazyBindingsType) |
227 |
| - .map(clazz -> clazz.isInstance(bindings)) |
228 |
| - .orElse(false); |
| 86 | + return bindings instanceof LazyBindings; |
229 | 87 | }
|
230 | 88 |
|
231 | 89 | /**
|
|
0 commit comments