SLING-9006 : Remove contention on sling request listener manager
diff --git a/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java b/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java
index 5f94c31..7451c76 100644
--- a/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java
+++ b/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java
@@ -61,6 +61,7 @@
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
import org.osgi.service.component.propertytypes.ServiceDescription;
import org.osgi.service.component.propertytypes.ServiceVendor;
import org.osgi.service.http.context.ServletContextHelper;
@@ -139,6 +140,9 @@
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
private volatile AdapterManager adapterManager;
+ @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY)
+ private volatile RequestListenerManager requestListenerManager;
+
private BundleContext bundleContext;
/** default log */
@@ -183,8 +187,6 @@
*/
private volatile String serverInfo = PRODUCT_NAME;
- private volatile RequestListenerManager requestListenerManager;
-
private volatile boolean allowTrace;
// new properties
@@ -227,7 +229,10 @@
// set the thread name according to the request
String threadName = setThreadName(request);
- requestListenerManager.sendEvent( request, SlingRequestEvent.EventType.EVENT_INIT );
+ final RequestListenerManager localRLM = requestListenerManager;
+ if (localRLM != null) {
+ localRLM.sendEvent(request, SlingRequestEvent.EventType.EVENT_INIT);
+ }
ResourceResolver resolver = null;
try {
@@ -269,7 +274,9 @@
resolver.close();
}
- requestListenerManager.sendEvent( request, SlingRequestEvent.EventType.EVENT_DESTROY );
+ if (localRLM != null) {
+ localRLM.sendEvent(request, SlingRequestEvent.EventType.EVENT_DESTROY);
+ }
// reset the thread name
if (threadName != null) {
@@ -497,9 +504,6 @@
filterManager.open();
requestProcessor.setFilterManager(filterManager);
- // initialize requestListenerManager
- requestListenerManager = new RequestListenerManager(bundleContext, slingServletContext);
-
try {
Dictionary<String, String> mbeanProps = new Hashtable<>();
mbeanProps.put("jmx.objectname", "org.apache.sling:type=engine,service=RequestProcessor");
@@ -547,13 +551,6 @@
this.servletRegistration = null;
}
- // dispose of request listener manager after unregistering the servlet
- // to prevent a potential NPE in the service method
- if ( this.requestListenerManager != null ) {
- this.requestListenerManager.dispose();
- this.requestListenerManager = null;
- }
-
// reset the sling main servlet reference (help GC and be nice)
RequestData.setSlingMainServlet(null);
diff --git a/src/main/java/org/apache/sling/engine/impl/helper/RequestListenerManager.java b/src/main/java/org/apache/sling/engine/impl/helper/RequestListenerManager.java
index 96a9174..4cd3fd0 100644
--- a/src/main/java/org/apache/sling/engine/impl/helper/RequestListenerManager.java
+++ b/src/main/java/org/apache/sling/engine/impl/helper/RequestListenerManager.java
@@ -18,38 +18,55 @@
*/
package org.apache.sling.engine.impl.helper;
+import java.util.List;
+
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.sling.api.request.SlingRequestEvent;
import org.apache.sling.api.request.SlingRequestListener;
-import org.osgi.framework.BundleContext;
-import org.osgi.util.tracker.ServiceTracker;
+import org.apache.sling.engine.impl.SlingMainServlet;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.FieldOption;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.propertytypes.ServiceDescription;
+import org.osgi.service.component.propertytypes.ServiceVendor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+@Component(service = RequestListenerManager.class)
+@ServiceDescription("Request listener manager")
+@ServiceVendor("The Apache Software Foundation")
public class RequestListenerManager {
- private final ServiceTracker serviceTracker;
-
private final ServletContext servletContext;
- public RequestListenerManager( final BundleContext context, final ServletContext servletContext ) {
- serviceTracker = new ServiceTracker( context, SlingRequestListener.SERVICE_NAME, null );
- serviceTracker.open();
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC, fieldOption = FieldOption.REPLACE)
+ private volatile List<SlingRequestListener> listeners;
+
+ @Activate
+ public RequestListenerManager(@Reference(target = "(name=" + SlingMainServlet.SERVLET_CONTEXT_NAME
+ + ")") final ServletContext servletContext) {
this.servletContext = servletContext;
}
public void sendEvent ( final HttpServletRequest request,
final SlingRequestEvent.EventType type) {
- final Object[] services = serviceTracker.getServices();
- if ( services != null && services.length > 0 ) {
+ final List<SlingRequestListener> local = listeners;
+ if (local != null && !local.isEmpty()) {
final SlingRequestEvent event = new SlingRequestEvent(this.servletContext, request, type);
- for ( final Object service : services ) {
- ( (SlingRequestListener) service ).onEvent( event );
+ for (final SlingRequestListener service : local) {
+ try {
+ service.onEvent(event);
+ } catch (final Throwable t) {
+ logger.error("Error invoking sling request listener " + service + " : " + t.getMessage(), t);
+ }
}
}
}
-
- public void dispose() {
- this.serviceTracker.close();
- }
}