Skip to content

Commit 8833320

Browse files
committed
re #2960 SCP BVP replace reflection with proper LazyBindings types
1 parent c610972 commit 8833320

File tree

8 files changed

+84
-381
lines changed

8 files changed

+84
-381
lines changed

bundle/pom.xml

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -41,37 +41,6 @@
4141
</archive>
4242
</configuration>
4343
</plugin>
44-
<plugin>
45-
<groupId>org.apache.maven.plugins</groupId>
46-
<artifactId>maven-dependency-plugin</artifactId>
47-
<executions>
48-
<execution>
49-
<!--
50-
this execution downloads org.apache.sling.api-2.22.0.jar for
51-
*TESTING* pre-6.5.7 LazyBindings support in our BindingsValuesProvider services,
52-
and specifically, SharedComponentPropertiesBindingsValuesProvider.
53-
-->
54-
<id>download-sling-api-2-22-0-jar</id>
55-
<phase>process-test-resources</phase>
56-
<goals>
57-
<goal>copy</goal>
58-
</goals>
59-
<configuration>
60-
<artifactItems>
61-
<item>
62-
<groupId>org.apache.sling</groupId>
63-
<artifactId>org.apache.sling.api</artifactId>
64-
<version>2.22.0</version>
65-
<type>jar</type>
66-
</item>
67-
</artifactItems>
68-
<!-- drop it into the target/test-classes directory -->
69-
<!-- required by SharedComponentPropertiesBindingsValuesProviderTest -->
70-
<outputDirectory>${project.build.testOutputDirectory}</outputDirectory>
71-
</configuration>
72-
</execution>
73-
</executions>
74-
</plugin>
7544
<plugin>
7645
<groupId>biz.aQute.bnd</groupId>
7746
<artifactId>bnd-baseline-maven-plugin</artifactId>
@@ -356,6 +325,8 @@
356325
<dependency>
357326
<groupId>org.osgi</groupId>
358327
<artifactId>org.osgi.dto</artifactId>
328+
<!-- defer to io.wcm.maven:io.wcm.maven.aem-dependencies managed version if possible -->
329+
<version>1.1.0</version>
359330
<scope>provided</scope>
360331
</dependency>
361332
<dependency>
@@ -383,11 +354,6 @@
383354
<artifactId>slf4j-api</artifactId>
384355
<scope>provided</scope>
385356
</dependency>
386-
<dependency>
387-
<groupId>javax.mail</groupId>
388-
<artifactId>mail</artifactId>
389-
<scope>provided</scope>
390-
</dependency>
391357
<!-- for com.adobe.acs.commons.logging.impl.SyslogAppender -->
392358
<dependency>
393359
<groupId>ch.qos.logback</groupId>
@@ -423,6 +389,8 @@
423389
<dependency>
424390
<groupId>com.github.jknack</groupId>
425391
<artifactId>handlebars</artifactId>
392+
<!-- defer to io.wcm.maven:io.wcm.maven.aem-dependencies managed version if possible -->
393+
<version>4.0.5</version>
426394
<scope>provided</scope>
427395
</dependency>
428396
<!-- END runtime dependencies not contained in uber-jar -->
@@ -745,7 +713,7 @@
745713
<dependency>
746714
<groupId>com.adobe.aem</groupId>
747715
<artifactId>uber-jar</artifactId>
748-
<classifier>apis</classifier>
716+
<classifier>apis-with-deprecations</classifier>
749717
<scope>provided</scope>
750718
</dependency>
751719
</dependencies>

bundle/src/main/java/com/adobe/acs/commons/wcm/properties/shared/impl/SharedComponentPropertiesBindingsValuesProvider.java

Lines changed: 7 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
package com.adobe.acs.commons.wcm.properties.shared.impl;
2121

2222
import com.adobe.acs.commons.wcm.properties.shared.SharedComponentProperties;
23-
import org.apache.felix.scr.annotations.Activate;
2423
import org.apache.felix.scr.annotations.Component;
2524
import org.apache.felix.scr.annotations.Reference;
2625
import org.apache.felix.scr.annotations.ReferenceCardinality;
@@ -29,18 +28,15 @@
2928
import org.apache.sling.api.SlingHttpServletRequest;
3029
import org.apache.sling.api.resource.Resource;
3130
import org.apache.sling.api.resource.ValueMap;
31+
import org.apache.sling.api.scripting.LazyBindings;
3232
import org.apache.sling.api.scripting.SlingBindings;
3333
import org.apache.sling.scripting.api.BindingsValuesProvider;
3434
import org.slf4j.Logger;
3535
import org.slf4j.LoggerFactory;
3636

3737
import javax.script.Bindings;
38-
import java.lang.reflect.InvocationHandler;
39-
import java.lang.reflect.Method;
40-
import java.lang.reflect.Proxy;
4138
import java.util.Optional;
4239
import java.util.function.Supplier;
43-
import java.util.stream.Stream;
4440

4541
/**
4642
* Bindings Values Provider that adds bindings for globalProperties,
@@ -62,170 +58,32 @@
6258
public class SharedComponentPropertiesBindingsValuesProvider implements BindingsValuesProvider {
6359
private static final Logger log = LoggerFactory.getLogger(SharedComponentPropertiesBindingsValuesProvider.class);
6460

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-
7261
/**
7362
* Bind if available, check for null when reading.
7463
*/
7564
@Reference(policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL_UNARY)
7665
SharedComponentProperties sharedComponentProperties;
7766

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-
13867
/**
13968
* This method ensures that the provided supplier is appropriately typed for insertion into a SlingBindings
14069
* 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).
14671
*
14772
* @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
20374
*/
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;
21777
}
21878

21979
/**
220-
* Check if provided {@code bindings} implements LazyBindings.
80+
* Check if provided {@code bindings} is an instance of {@link LazyBindings}.
22181
*
22282
* @param bindings the parameter from {@link #addBindings(Bindings)}
22383
* @return true if bindings implements LazyBindings
22484
*/
22585
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;
22987
}
23088

23189
/**

0 commit comments

Comments
 (0)