Author: kwin
Date: Thu Feb 26 12:27:25 2015
New Revision: 1662434

URL: http://svn.apache.org/r1662434
Log:
SLING-4447 provide a SlingModels Sightly UseProvider which throws exceptions in 
case a Sling Model cannot be instantiated instead of falling back to the simple 
Pojo instantiation.

Added:
    
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/sightly/
    
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/sightly/ModelFactoryUseProvider.java
Modified:
    sling/trunk/bundles/extensions/models/impl/pom.xml

Modified: sling/trunk/bundles/extensions/models/impl/pom.xml
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/pom.xml?rev=1662434&r1=1662433&r2=1662434&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/pom.xml (original)
+++ sling/trunk/bundles/extensions/models/impl/pom.xml Thu Feb 26 12:27:25 2015
@@ -146,5 +146,19 @@
             <scope>provided</scope>
             <optional>true</optional>
         </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.scripting.sightly</artifactId>
+            <version>1.0.0-SNAPSHOT</version>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.classloader</artifactId>
+            <version>1.3.0</version>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
     </dependencies>
 </project>

Added: 
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/sightly/ModelFactoryUseProvider.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/sightly/ModelFactoryUseProvider.java?rev=1662434&view=auto
==============================================================================
--- 
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/sightly/ModelFactoryUseProvider.java
 (added)
+++ 
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/sightly/ModelFactoryUseProvider.java
 Thu Feb 26 12:27:25 2015
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.models.impl.sightly;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.script.Bindings;
+import javax.servlet.ServletRequest;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.commons.classloader.DynamicClassLoaderManager;
+import org.apache.sling.models.factory.ModelFactory;
+import 
org.apache.sling.scripting.sightly.impl.engine.extension.use.UseProviderUtils;
+import org.apache.sling.scripting.sightly.render.RenderContext;
+import org.apache.sling.scripting.sightly.use.ProviderOutcome;
+import org.apache.sling.scripting.sightly.use.UseProvider;
+import org.osgi.framework.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Sightly {@code UseProvider} which will instantiate a referenced Sling Model.
+ * It will always fail with an exception (i.e. no other {@code UseProvider} is 
asked afterwards and the exception is being rethrown)
+ * in case the following two preconditions are fulfilled:
+ * 1. the given identifier specifies a class which can be loaded by the 
DynamicClassLoader
+ * 2. the loaded class has a Model annotation
+ * In case any of those preconditions are not fulfilled, the other registered 
UseProviders are used!
+ */
+@Component
+@Service
+/*
+ * must have a higher priority than 
org.apache.sling.scripting.sightly.impl.engine.extension.use.JavaUseProvider 
but lower than 
+ * 
org.apache.sling.scripting.sightly.impl.engine.extension.use.RenderUnitProvider 
to kick in 
+ * before the JavaUserProvider but after the RenderUnitProvider
+ */
+@Property(name = Constants.SERVICE_RANKING, intValue = { 95 }) 
+public class ModelFactoryUseProvider implements UseProvider {
+
+    private static final Logger log = 
LoggerFactory.getLogger(ModelFactoryUseProvider.class);
+    
+    @Reference
+    ModelFactory modelFactory;
+    
+    @Reference
+    private DynamicClassLoaderManager dynamicClassLoaderManager = null;
+    
+    @Override
+    public ProviderOutcome provide(final String identifier,
+            final RenderContext renderContext, final Bindings arguments) {
+        final Class<?> cls;
+        try {
+            cls = 
dynamicClassLoaderManager.getDynamicClassLoader().loadClass(identifier);
+        } catch(ClassNotFoundException e) {
+            log.debug("Could not find class with the given name {}: {}", 
identifier, e.getMessage());
+            // next use provider will be queried
+            return ProviderOutcome.failure();
+        }
+        Bindings globalBindings = renderContext.getBindings();
+        Bindings bindings = UseProviderUtils.merge(globalBindings, arguments);
+        Resource resource = (Resource) bindings.get(SlingBindings.RESOURCE);
+        if (resource == null) {
+            return ProviderOutcome.failure(new IllegalStateException("Could 
not get resource from bindings"));
+        }
+        SlingHttpServletRequest request = (SlingHttpServletRequest) 
bindings.get(SlingBindings.REQUEST);
+        if (request == null) {
+            return ProviderOutcome.failure(new IllegalStateException("Could 
not get request from bindings"));
+        }
+
+        // pass parameters as request attributes
+        Map<String, Object> overrides = setRequestAttributes(request, 
arguments);
+        Object obj = null;
+        try {
+            if (!modelFactory.isModelClass(resource, cls)) {
+                log.debug("{} is no Sling Model (because it lacks the 
according Model annotation)!");
+                // next use provider will be queried
+                return ProviderOutcome.failure();
+            }
+            // try to instantiate class via Sling Models (first via resource, 
then via request)
+            if (modelFactory.canCreateFromAdaptable(resource, cls)) {
+                obj = modelFactory.createModel(resource, cls);
+            } else if (modelFactory.canCreateFromAdaptable(request, cls)) {
+                obj = modelFactory.createModel(request, cls);
+            } else {
+                return ProviderOutcome.failure(new 
IllegalStateException("Could not adapt the given Sling Model from neither 
resource nor request: " + cls));
+            }
+        } catch (Throwable e) {
+            return ProviderOutcome.failure(e);
+        } finally {
+            resetRequestAttribute(request, overrides);
+        }
+        return ProviderOutcome.notNullOrFailure(obj);
+    }
+
+    private Map<String, Object> setRequestAttributes(final ServletRequest 
request,
+            final Bindings arguments) {
+        Map<String, Object> overrides = new HashMap<String, Object>();
+        for (Map.Entry<String, Object> entry : arguments.entrySet()) {
+            String key = entry.getKey();
+            Object value = entry.getValue();
+            Object oldValue = request.getAttribute(key);
+            if (oldValue != null) {
+                overrides.put(key, oldValue);
+            }
+            else {
+                overrides.put(key, null);
+            }
+            request.setAttribute(key, value);
+        }
+        return overrides;
+    }
+
+    private void resetRequestAttribute(final ServletRequest request,
+            final Map<String, Object> overrides) {
+        for (Map.Entry<String, Object> entry : overrides.entrySet()) {
+            String key = entry.getKey();
+            Object value = entry.getValue();
+            if (value == null) {
+                request.removeAttribute(key);
+            }
+            else {
+                request.setAttribute(key, value);
+            }
+        }
+    }
+}


Reply via email to