You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ju...@apache.org on 2016/11/30 17:09:57 UTC

svn commit: r1772085 - in /sling/trunk/bundles/extensions/models/impl/src: main/java/org/apache/sling/models/impl/ main/java/org/apache/sling/models/impl/injectors/ test/java/org/apache/sling/models/impl/ test/java/org/apache/sling/models/testmodels/cl...

Author: justin
Date: Wed Nov 30 17:09:57 2016
New Revision: 1772085

URL: http://svn.apache.org/viewvc?rev=1772085&view=rev
Log:
SLING-6318 - internal optimization to avoid repeated retrieval of ValueMap from Resource

Added:
    sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ValuePreparer.java
      - copied, changed from r1770770, sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/BindingsModel.java
Modified:
    sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
    sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/BindingsInjector.java
    sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java
    sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java
    sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java
    sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java
    sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/BindingsModel.java
    sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/BindingsModel.java

Modified: sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java?rev=1772085&r1=1772084&r2=1772085&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java (original)
+++ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java Wed Nov 30 17:09:57 2016
@@ -43,6 +43,7 @@ import javax.annotation.Nonnull;
 import javax.annotation.PostConstruct;
 
 import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.commons.lang.ObjectUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
@@ -73,6 +74,7 @@ import org.apache.sling.models.factory.M
 import org.apache.sling.models.factory.ModelFactory;
 import org.apache.sling.models.factory.PostConstructException;
 import org.apache.sling.models.factory.ValidationException;
+import org.apache.sling.models.impl.injectors.ValuePreparer;
 import org.apache.sling.models.impl.model.ConstructorParameter;
 import org.apache.sling.models.impl.model.InjectableElement;
 import org.apache.sling.models.impl.model.InjectableField;
@@ -109,6 +111,9 @@ import org.slf4j.LoggerFactory;
 @SuppressWarnings("deprecation")
 public class ModelAdapterFactory implements AdapterFactory, Runnable, ModelFactory {
 
+    // hard code this value since we always know exactly how many there are
+    private static final int VALUE_PREPARERS_COUNT = 2;
+
     private static class DisposalCallbackRegistryImpl implements DisposalCallbackRegistry {
 
         private List<DisposalCallback> callbacks = new ArrayList<DisposalCallback>();
@@ -402,7 +407,8 @@ public class ModelAdapterFactory impleme
     private
     @CheckForNull
     RuntimeException injectElement(final InjectableElement element, final Object adaptable,
-                                   final @Nonnull DisposalCallbackRegistry registry, final InjectCallback callback) {
+                                   final @Nonnull DisposalCallbackRegistry registry, final InjectCallback callback,
+                                   final @Nonnull Map<ValuePreparer, Object> preparedValues) {
 
         InjectAnnotationProcessor annotationProcessor = null;
         String source = element.getSource();
@@ -425,7 +431,7 @@ public class ModelAdapterFactory impleme
         }
 
         String name = getName(element, annotationProcessor);
-        Object injectionAdaptable = getAdaptable(adaptable, element, annotationProcessor);
+        final Object injectionAdaptable = getAdaptable(adaptable, element, annotationProcessor);
 
         RuntimeException lastInjectionException = null;
         if (injectionAdaptable != null) {
@@ -445,7 +451,29 @@ public class ModelAdapterFactory impleme
             // find the right injector
             for (Injector injector : injectorsToProcess) {
                 if (name != null || injector instanceof AcceptsNullName) {
-                    Object value = injector.getValue(injectionAdaptable, name, element.getType(), element.getAnnotatedElement(), registry);
+                    Object preparedValue = injectionAdaptable;
+
+                    // only do the ValuePreparer optimization for the original adaptable
+                    if (injector instanceof ValuePreparer && adaptable == injectionAdaptable) {
+                        final ValuePreparer preparer = (ValuePreparer) injector;
+                        Object fromMap = preparedValues.get(preparer);
+                        if (fromMap != null) {
+                            if (ObjectUtils.NULL.equals(fromMap)) {
+                                preparedValue = null;
+                            } else {
+                                preparedValue = fromMap;
+                            }
+                        } else {
+                            preparedValue = preparer.prepareValue(injectionAdaptable);
+                            if (preparedValue == null) {
+                                preparedValues.put(preparer, ObjectUtils.NULL);
+                            } else {
+                                preparedValues.put(preparer, preparedValue);
+                            }
+                        }
+                    }
+
+                    Object value = injector.getValue(preparedValue, name, element.getType(), element.getAnnotatedElement(), registry);
                     if (value != null) {
                         lastInjectionException = callback.inject(element, value);
                         if (lastInjectionException == null) {
@@ -503,9 +531,11 @@ public class ModelAdapterFactory impleme
         DisposalCallbackRegistryImpl registry = new DisposalCallbackRegistryImpl();
         registerCallbackRegistry(handler, registry);
 
+        final Map<ValuePreparer, Object> preparedValues = new HashMap<ValuePreparer, Object>(VALUE_PREPARERS_COUNT);
+
         MissingElementsException missingElements = new MissingElementsException("Could not create all mandatory methods for interface of model " + modelClass);
         for (InjectableMethod method : injectableMethods) {
-            RuntimeException t = injectElement(method, adaptable, registry, callback);
+            RuntimeException t = injectElement(method, adaptable, registry, callback, preparedValues);
             if (t != null) {
                 missingElements.addMissingElementExceptions(new MissingElementException(method.getAnnotatedElement(), t));
             }
@@ -531,6 +561,8 @@ public class ModelAdapterFactory impleme
             return new Result<ModelType>(new ModelClassException("Unable to find a useable constructor for model " + modelClass.getType()));
         }
 
+        final Map<ValuePreparer, Object> preparedValues = new HashMap<ValuePreparer, Object>(VALUE_PREPARERS_COUNT);
+
         final ModelType object;
         if (constructorToUse.getConstructor().getParameterTypes().length == 0) {
             // no parameters for constructor injection? instantiate it right away
@@ -539,7 +571,7 @@ public class ModelAdapterFactory impleme
             // instantiate with constructor injection
             // if this fails, make sure resources that may be claimed by injectors are cleared up again
             try {
-                Result<ModelType> result = newInstanceWithConstructorInjection(constructorToUse, adaptable, modelClass, registry);
+                Result<ModelType> result = newInstanceWithConstructorInjection(constructorToUse, adaptable, modelClass, registry, preparedValues);
                 if (!result.wasSuccessful()) {
                     registry.onDisposed();
                     return result;
@@ -564,8 +596,9 @@ public class ModelAdapterFactory impleme
 
         InjectableField[] injectableFields = modelClass.getInjectableFields();
         MissingElementsException missingElements = new MissingElementsException("Could not inject all required fields into " + modelClass.getType());
+
         for (InjectableField field : injectableFields) {
-            RuntimeException t = injectElement(field, adaptable, registry, callback);
+            RuntimeException t = injectElement(field, adaptable, registry, callback, preparedValues);
             if (t != null) {
                 missingElements.addMissingElementExceptions(new MissingElementException(field.getAnnotatedElement(), t));
             }
@@ -618,7 +651,7 @@ public class ModelAdapterFactory impleme
     }
 
     private <ModelType> Result<ModelType> newInstanceWithConstructorInjection(final ModelClassConstructor<ModelType> constructor, final Object adaptable,
-            final ModelClass<ModelType> modelClass, final DisposalCallbackRegistry registry)
+            final ModelClass<ModelType> modelClass, final DisposalCallbackRegistry registry, final @Nonnull Map<ValuePreparer, Object> preparedValues)
             throws InstantiationException, InvocationTargetException, IllegalAccessException {
         ConstructorParameter[] parameters = constructor.getConstructorParameters();
 
@@ -627,7 +660,7 @@ public class ModelAdapterFactory impleme
 
         MissingElementsException missingElements = new MissingElementsException("Required constructor parameters were not able to be injected on model " + modelClass.getType());
         for (int i = 0; i < parameters.length; i++) {
-            RuntimeException t = injectElement(parameters[i], adaptable, registry, callback);
+            RuntimeException t = injectElement(parameters[i], adaptable, registry, callback, preparedValues);
             if (t != null) {
                 missingElements.addMissingElementExceptions(new MissingElementException(parameters[i].getAnnotatedElement(), t));
             }

Modified: sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/BindingsInjector.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/BindingsInjector.java?rev=1772085&r1=1772084&r2=1772085&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/BindingsInjector.java (original)
+++ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/BindingsInjector.java Wed Nov 30 17:09:57 2016
@@ -40,7 +40,7 @@ import org.slf4j.LoggerFactory;
 @Component
 @Service
 @Property(name = Constants.SERVICE_RANKING, intValue = 1000)
-public class BindingsInjector implements Injector, StaticInjectAnnotationProcessorFactory {
+public class BindingsInjector implements Injector, StaticInjectAnnotationProcessorFactory, ValuePreparer {
 
     private static final Logger log = LoggerFactory.getLogger(BindingsInjector.class);
 
@@ -64,7 +64,9 @@ public class BindingsInjector implements
     }
 
     private SlingBindings getBindings(Object adaptable) {
-        if (adaptable instanceof ServletRequest) {
+        if (adaptable instanceof SlingBindings) {
+            return (SlingBindings) adaptable;
+        } else if (adaptable instanceof ServletRequest) {
             ServletRequest request = (ServletRequest) adaptable;
             return (SlingBindings) request.getAttribute(SlingBindings.class.getName());
         } else {
@@ -82,6 +84,11 @@ public class BindingsInjector implements
         return null;
     }
 
+    @Override
+    public Object prepareValue(Object adaptable) {
+        return getBindings(adaptable);
+    }
+
     private static class ScriptVariableAnnotationProcessor extends AbstractInjectAnnotationProcessor2 {
 
         private final ScriptVariable annotation;

Modified: sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java?rev=1772085&r1=1772084&r2=1772085&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java (original)
+++ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java Wed Nov 30 17:09:57 2016
@@ -48,7 +48,7 @@ import org.slf4j.LoggerFactory;
 @Service
 @Property(name = Constants.SERVICE_RANKING, intValue = 2000)
 @SuppressWarnings("deprecation")
-public class ValueMapInjector extends AbstractInjector implements Injector, InjectAnnotationProcessorFactory {
+public class ValueMapInjector extends AbstractInjector implements Injector, InjectAnnotationProcessorFactory, ValuePreparer {
 
     private static final Logger log = LoggerFactory.getLogger(ValueMapInjector.class);
 
@@ -134,6 +134,11 @@ public class ValueMapInjector extends Ab
     }
 
     @Override
+    public Object prepareValue(final Object adaptable) {
+        return getValueMap(adaptable);
+    }
+
+    @Override
     public InjectAnnotationProcessor createAnnotationProcessor(Object adaptable, AnnotatedElement element) {
         // check if the element has the expected annotation
         ValueMapValue annotation = element.getAnnotation(ValueMapValue.class);

Copied: sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ValuePreparer.java (from r1770770, sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/BindingsModel.java)
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ValuePreparer.java?p2=sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ValuePreparer.java&p1=sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/BindingsModel.java&r1=1770770&r2=1772085&rev=1772085&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/BindingsModel.java (original)
+++ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ValuePreparer.java Wed Nov 30 17:09:57 2016
@@ -14,24 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sling.models.testmodels.classes;
+package org.apache.sling.models.impl.injectors;
 
-import javax.inject.Inject;
-import javax.inject.Named;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
 
-import org.apache.sling.api.SlingHttpServletRequest;
-import org.apache.sling.api.scripting.SlingScriptHelper;
-import org.apache.sling.models.annotations.Model;
-
-@Model(adaptables=SlingHttpServletRequest.class)
-public class BindingsModel {
-    
-    @Inject
-    @Named("sling")
-    private SlingScriptHelper sling;
-    
-    public SlingScriptHelper getSling() {
-        return sling;
-    }
+public interface ValuePreparer {
 
+    @CheckForNull Object prepareValue(@Nonnull Object adaptable);
 }

Modified: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java?rev=1772085&r1=1772084&r2=1772085&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java (original)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java Wed Nov 30 17:09:57 2016
@@ -19,6 +19,8 @@ package org.apache.sling.models.impl;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.times;
 
 import java.util.Hashtable;
 
@@ -34,6 +36,7 @@ import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.component.ComponentContext;
+import org.slf4j.LoggerFactory;
 
 @RunWith(MockitoJUnitRunner.class)
 public class RequestInjectionTest {
@@ -59,6 +62,7 @@ public class RequestInjectionTest {
 
         SlingBindings bindings = new SlingBindings();
         bindings.setSling(sling);
+        bindings.setLog(LoggerFactory.getLogger("test"));
         when(request.getAttribute(SlingBindings.class.getName())).thenReturn(bindings);
 
         factory = new ModelAdapterFactory();
@@ -73,6 +77,8 @@ public class RequestInjectionTest {
         BindingsModel model = factory.getAdapter(request, BindingsModel.class);
         assertNotNull(model.getSling());
         assertEquals(sling, model.getSling());
+        assertEquals("test", model.getLog().getName());
+        verify(request, times(1)).getAttribute(SlingBindings.class.getName());
     }
 
     @Test
@@ -81,6 +87,9 @@ public class RequestInjectionTest {
                 = factory.getAdapter(request, org.apache.sling.models.testmodels.classes.constructorinjection.BindingsModel.class);
         assertNotNull(model.getSling());
         assertEquals(sling, model.getSling());
+        assertEquals("test", model.getLog().getName());
+
+        verify(request, times(1)).getAttribute(SlingBindings.class.getName());
     }
 
 }

Modified: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java?rev=1772085&r1=1772084&r2=1772085&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java (original)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java Wed Nov 30 17:09:57 2016
@@ -105,6 +105,8 @@ public class ResourceModelClassesTest {
         assertEquals("three", array[0]);
 
         assertTrue(model.isPostConstructCalled());
+
+        verify(res, times(1)).adaptTo(ValueMap.class);
     }
 
     @Test

Modified: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java?rev=1772085&r1=1772084&r2=1772085&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java (original)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java Wed Nov 30 17:09:57 2016
@@ -87,6 +87,8 @@ public class ResourceModelInterfacesTest
         assertNull(model.getSecond());
         assertEquals("third-value", model.getThirdProperty());
         assertTrue(model.isFourth());
+
+        verify(res, times(1)).adaptTo(ValueMap.class);
     }
 
     @Test

Modified: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/BindingsModel.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/BindingsModel.java?rev=1772085&r1=1772084&r2=1772085&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/BindingsModel.java (original)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/BindingsModel.java Wed Nov 30 17:09:57 2016
@@ -22,6 +22,7 @@ import javax.inject.Named;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.scripting.SlingScriptHelper;
 import org.apache.sling.models.annotations.Model;
+import org.slf4j.Logger;
 
 @Model(adaptables=SlingHttpServletRequest.class)
 public class BindingsModel {
@@ -29,9 +30,16 @@ public class BindingsModel {
     @Inject
     @Named("sling")
     private SlingScriptHelper sling;
+
+    @Inject
+    private Logger log;
     
     public SlingScriptHelper getSling() {
         return sling;
     }
 
+    public Logger getLog() {
+        return log;
+    }
+
 }

Modified: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/BindingsModel.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/BindingsModel.java?rev=1772085&r1=1772084&r2=1772085&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/BindingsModel.java (original)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/BindingsModel.java Wed Nov 30 17:09:57 2016
@@ -22,12 +22,17 @@ import javax.inject.Named;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.scripting.SlingScriptHelper;
 import org.apache.sling.models.annotations.Model;
+import org.slf4j.Logger;
 
 @Model(adaptables = SlingHttpServletRequest.class)
 public class BindingsModel {
 
     private final SlingScriptHelper sling;
 
+
+    @Inject
+    private Logger log;
+
     @Inject
     public BindingsModel(@Named("sling") SlingScriptHelper sling) {
         this.sling = sling;
@@ -37,4 +42,7 @@ public class BindingsModel {
         return sling;
     }
 
+    public Logger getLog() {
+        return log;
+    }
 }
\ No newline at end of file