Add default dispatcher for resource types without versions and fix dependency lookup with versions
diff --git a/pom.xml b/pom.xml
index 25ee3d5..dc8ff4c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -270,7 +270,7 @@
<configuration>
<usePomDependencies>true</usePomDependencies>
<attachArtifact>false</attachArtifact>
- <shouldBlockUntilKeyIsPressed>true</shouldBlockUntilKeyIsPressed>
+ <!-- <shouldBlockUntilKeyIsPressed>true</shouldBlockUntilKeyIsPressed> -->
<servers>
<server>
<id>singleinstance</id>
diff --git a/src/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptServlet.java b/src/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptServlet.java
index 0bd91a6..0c1f0ca 100644
--- a/src/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptServlet.java
+++ b/src/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptServlet.java
@@ -52,20 +52,22 @@
private final BundledScriptFinder m_bundledScriptFinder;
private final ScriptContextProvider m_scriptContextProvider;
private final String m_delegatedResourceType;
+ private final Set<String> m_wiredResourceTypes;
private Map<String, Script> scriptsMap = new HashMap<>();
private ReadWriteLock lock = new ReentrantReadWriteLock();
- BundledScriptServlet(BundledScriptFinder bundledScriptFinder, Bundle bundle, ScriptContextProvider scriptContextProvider) {
- this(bundledScriptFinder, bundle, scriptContextProvider, null);
+ BundledScriptServlet(BundledScriptFinder bundledScriptFinder, Bundle bundle, ScriptContextProvider scriptContextProvider, Set<String> wiredResourceTypes) {
+ this(bundledScriptFinder, bundle, scriptContextProvider, null, wiredResourceTypes );
}
BundledScriptServlet(BundledScriptFinder bundledScriptFinder, Bundle bundle, ScriptContextProvider scriptContextProvider, String
- overridingResourceType) {
+ overridingResourceType, Set<String> wiredResourceTypes) {
m_bundle = bundle;
m_bundledScriptFinder = bundledScriptFinder;
m_scriptContextProvider = scriptContextProvider;
m_delegatedResourceType = overridingResourceType;
+ m_wiredResourceTypes = wiredResourceTypes;
}
@Override
@@ -112,7 +114,7 @@
lock.readLock().unlock();
}
if (script != null) {
- RequestWrapper requestWrapper = new RequestWrapper(request, getWiredResourceTypes());
+ RequestWrapper requestWrapper = new RequestWrapper(request, m_wiredResourceTypes);
ScriptContext scriptContext = m_scriptContextProvider.prepareScriptContext(requestWrapper, response, script);
try {
script.eval(scriptContext);
@@ -135,28 +137,4 @@
return request.getResource().getResourceType() + (StringUtils.isNotEmpty(selectorString) ? ":" + selectorString : "") +
(StringUtils.isNotEmpty(requestExtension) ? ":" + requestExtension : "");
}
-
- private Set<String> getWiredResourceTypes() {
- Set<String> wiredResourceTypes = new HashSet<>();
- BundleWiring bundleWiring = m_bundle.adapt(BundleWiring.class);
- bundleWiring.getProvidedWires(BundledScriptTracker.NS_SLING_RESOURCE_TYPE).forEach(
- bundleWire -> {
- String resourceType = (String) bundleWire.getCapability().getAttributes().get(BundledScriptTracker
- .NS_SLING_RESOURCE_TYPE);
- Version version = (Version) bundleWire.getCapability().getAttributes().get(BundledScriptTracker
- .AT_VERSION);
- wiredResourceTypes.add(resourceType + (version == null ? "" : "/" + version.toString()));
- }
- );
- bundleWiring.getRequiredWires(BundledScriptTracker.NS_SLING_RESOURCE_TYPE).forEach(
- bundleWire -> {
- String resourceType = (String) bundleWire.getCapability().getAttributes().get(BundledScriptTracker
- .NS_SLING_RESOURCE_TYPE);
- Version version = (Version) bundleWire.getCapability().getAttributes().get(BundledScriptTracker
- .AT_VERSION);
- wiredResourceTypes.add(resourceType + (version == null ? "" : "/" + version.toString()));
- }
- );
- return wiredResourceTypes;
- }
}
diff --git a/src/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptTracker.java b/src/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptTracker.java
index 406a225..e70ca8a 100644
--- a/src/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptTracker.java
+++ b/src/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptTracker.java
@@ -18,24 +18,44 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package org.apache.sling.scripting.resolver.internal;
+import java.io.IOException;
+import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.servlet.GenericServlet;
+import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.request.RequestDispatcherOptions;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ResourceWrapper;
+import org.apache.sling.api.resource.SyntheticResource;
import org.apache.sling.api.servlets.ServletResolverConstants;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
+import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.Version;
import org.osgi.framework.wiring.BundleCapability;
@@ -103,8 +123,6 @@
{
Hashtable<String, Object> properties = new Hashtable<>();
- List<ServiceRegistration<Servlet>> result = new ArrayList<>();
-
Map<String, Object> attributes = cap.getAttributes();
String resourceType = (String) attributes.get(NS_SLING_RESOURCE_TYPE);
@@ -145,26 +163,39 @@
).findFirst();
}
+ List<ServiceRegistration<Servlet>> regs = new ArrayList<>();
+
if (optionalWire.isPresent()) {
BundleWire extendsWire = optionalWire.get();
Map<String, Object> wireCapabilityAttributes = extendsWire.getCapability().getAttributes();
String wireResourceType = (String) wireCapabilityAttributes.get(NS_SLING_RESOURCE_TYPE);
Version wireResourceTypeVersion = (Version) wireCapabilityAttributes.get(AT_VERSION);
- result.add(bundle.getBundleContext().registerService(
+ regs.add(bundle.getBundleContext().registerService(
Servlet.class,
new BundledScriptServlet(bundledScriptFinder, optionalWire.get().getProvider().getBundle(),
- scriptContextProvider, wireResourceType + (StringUtils.isNotEmpty(wireResourceType) ? "/" +
- wireResourceTypeVersion.toString() : "")),
+ scriptContextProvider, wireResourceType + (wireResourceTypeVersion != null ? "/" +
+ wireResourceTypeVersion.toString() : ""), getWiredResourceTypes(
+ new HashSet<>(Arrays.asList((String) attributes.get(NS_SLING_RESOURCE_TYPE), wireResourceType)),
+ new HashSet<>(Arrays.asList(resourceType, wireResourceType + (wireResourceTypeVersion != null ? "/" +
+ wireResourceTypeVersion.toString() : ""))),
+ bundle,optionalWire.get().getProvider().getBundle())),
properties
));
}
else
{
- result.add(bundle.getBundleContext()
- .registerService(Servlet.class, new BundledScriptServlet(bundledScriptFinder, bundle, scriptContextProvider),
+ regs.add(bundle.getBundleContext()
+ .registerService(Servlet.class, new BundledScriptServlet(bundledScriptFinder, bundle, scriptContextProvider,
+ getWiredResourceTypes(new HashSet<>(Arrays.asList((String) attributes.get(NS_SLING_RESOURCE_TYPE))),
+ new HashSet<>(Arrays.asList(resourceType)),bundle)),
properties));
}
- return result.stream();
+ if (version != null)
+ {
+ properties.put(ServletResolverConstants.SLING_SERVLET_RESOURCE_TYPES, attributes.get(NS_SLING_RESOURCE_TYPE));
+ regs.add(m_context.registerService(Servlet.class, new DispatcherServlet((String) attributes.get(NS_SLING_RESOURCE_TYPE)), properties));
+ }
+ return regs.stream();
}).collect(Collectors.toList());
} else {
return null;
@@ -174,6 +205,94 @@
}
}
+
+
+ private Set<String> getWiredResourceTypes(Set<String> rts, Set<String> initial, Bundle... bundles) {
+ Set<String> wiredResourceTypes = new HashSet<>();
+ wiredResourceTypes.addAll(initial);
+ for (Bundle bundle : bundles)
+ {
+ BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
+ bundleWiring.getCapabilities(BundledScriptTracker.NS_SLING_RESOURCE_TYPE).forEach(
+ cap ->
+ {
+ String resourceType = (String) cap.getAttributes().get(BundledScriptTracker
+ .NS_SLING_RESOURCE_TYPE);
+ Version version = (Version) cap.getAttributes().get(BundledScriptTracker
+ .AT_VERSION);
+ if (!rts.contains(resourceType))
+ {
+ wiredResourceTypes.add(resourceType + (version == null ? "" : "/" + version.toString()));
+ }
+ }
+ );
+ bundleWiring.getRequiredWires(BundledScriptTracker.NS_SLING_RESOURCE_TYPE).forEach(
+ bundleWire ->
+ {
+ String resourceType = (String) bundleWire.getCapability().getAttributes().get(BundledScriptTracker
+ .NS_SLING_RESOURCE_TYPE);
+ Version version = (Version) bundleWire.getCapability().getAttributes().get(BundledScriptTracker
+ .AT_VERSION);
+ if (!rts.contains(resourceType))
+ {
+ wiredResourceTypes.add(resourceType + (version == null ? "" : "/" + version.toString()));
+ }
+ }
+ );
+ }
+ return wiredResourceTypes;
+ }
+
+ private Hashtable<String, Object> toProperties(ServiceRegistration<?> reg)
+ {
+ Hashtable<String, Object> result = new Hashtable<>();
+ ServiceReference<?> ref = reg.getReference();
+
+ set(ServletResolverConstants.SLING_SERVLET_RESOURCE_TYPES, ref, result);
+ set(ServletResolverConstants.SLING_SERVLET_EXTENSIONS, ref, result);
+ set(ServletResolverConstants.SLING_SERVLET_SELECTORS, ref, result);
+ set(ServletResolverConstants.SLING_SERVLET_METHODS, ref, result);
+
+ return result;
+ }
+
+ private String getResourceType(Hashtable<String, Object> props)
+ {
+ String[] values = PropertiesUtil.toStringArray(props.get(ServletResolverConstants.SLING_SERVLET_RESOURCE_TYPES));
+ int idx = values[0].indexOf("/");
+ if (idx != -1)
+ {
+ return values[0].substring(0, idx);
+ }
+ else
+ {
+ return values[0];
+ }
+ }
+
+ private String getResourceTypeVersion(ServiceReference<?>ref )
+ {
+ String[] values = PropertiesUtil.toStringArray(ref.getProperty(ServletResolverConstants.SLING_SERVLET_RESOURCE_TYPES));
+ int idx = values[0].indexOf("/");
+ if (idx != -1)
+ {
+ return values[0].substring(idx + 1);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ private void set(String key, ServiceReference<?> ref, Hashtable<String, Object> props)
+ {
+ Object value = ref.getProperty(key);
+ if (value != null)
+ {
+ props.put(key, value);
+ }
+ }
+
@Override
public void modifiedBundle(Bundle bundle, BundleEvent event, List<ServiceRegistration<Servlet>> regs) {
LOGGER.warn(String.format("Unexpected modified event: %s for bundle %s", event.toString(), bundle.toString()));
@@ -185,4 +304,69 @@
regs.forEach(ServiceRegistration::unregister);
}
+ private class DispatcherServlet extends GenericServlet
+ {
+ private final String m_rt;
+
+ DispatcherServlet(String rt)
+ {
+ m_rt = rt;
+ }
+
+ @Override
+ public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
+ {
+ SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) req;
+
+ Optional<ServiceRegistration<Servlet>> target = m_tracker.getTracked().values().stream().flatMap(List::stream)
+ .filter(
+ ((Predicate<ServiceRegistration<Servlet>>) reg -> reg.getReference().getBundle().equals(m_context.getBundle())).negate()
+ )
+ .filter(reg -> getResourceTypeVersion(reg.getReference()) != null)
+ .filter(reg ->
+ {
+ Hashtable<String, Object> props = toProperties(reg);
+ if (getResourceType(props).equals(m_rt))
+ {
+ if (Arrays.asList(PropertiesUtil.toStringArray(props.get(ServletResolverConstants.SLING_SERVLET_SELECTORS), new String[0]))
+ .containsAll(Arrays.asList(slingRequest.getRequestPathInfo().getSelectors()))
+ &&
+ Arrays.asList(PropertiesUtil.toStringArray(props.get(ServletResolverConstants.SLING_SERVLET_METHODS), new String[]{"GET", "HEAD"}))
+ .contains(slingRequest.getMethod())
+ &&
+ Arrays.asList(PropertiesUtil.toStringArray(props.get(ServletResolverConstants.SLING_SERVLET_EXTENSIONS), new String[]{"html"}))
+ .contains(slingRequest.getRequestPathInfo().getExtension() == null ? "html" : slingRequest.getRequestPathInfo().getExtension() ))
+ {
+ return true;
+ }
+ }
+ return false;
+ })
+ .sorted(Comparator.comparing(reg -> new Version(getResourceTypeVersion(reg.getReference())), Comparator.reverseOrder()))
+ .findFirst();
+
+ if (target.isPresent())
+ {
+ String rt = (String) target.get().getReference().getProperty(ServletResolverConstants.SLING_SERVLET_RESOURCE_TYPES);
+ RequestDispatcherOptions options = new RequestDispatcherOptions();
+ options.setForceResourceType(rt);
+
+ System.out.println("found: " + rt);
+ RequestDispatcher dispatcher = slingRequest.getRequestDispatcher(slingRequest.getResource(), options);
+ if (dispatcher != null)
+ {
+ dispatcher.forward(req, res);
+ }
+ else
+ {
+ ((SlingHttpServletResponse) res).sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+ }
+ else
+ {
+ System.out.println("Not found");
+ ((SlingHttpServletResponse) res).sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+ }
+ }
}
diff --git a/src/main/java/org/apache/sling/scripting/resolver/internal/RequestWrapper.java b/src/main/java/org/apache/sling/scripting/resolver/internal/RequestWrapper.java
index f1ad7c0..536f3bb 100644
--- a/src/main/java/org/apache/sling/scripting/resolver/internal/RequestWrapper.java
+++ b/src/main/java/org/apache/sling/scripting/resolver/internal/RequestWrapper.java
@@ -42,6 +42,17 @@
if (resource == null) {
return null;
}
+ if (StringUtils.isEmpty(options.getForceResourceType()))
+ {
+ if (!StringUtils.isEmpty(resource.getResourceType()))
+ {
+ options.setForceResourceType(resource.getResourceType());
+ }
+ else if (!StringUtils.isEmpty(resource.getResourceSuperType()))
+ {
+ options.setForceResourceType(resource.getResourceSuperType());
+ }
+ }
RequestDispatcherOptions processedOptions = processOptions(options);
return super.getRequestDispatcher(resource, processedOptions);
}