![JAR search and dependency download from the Maven repository](/logo.png)
com.day.cq.commons.servlets.NonExistingDispatcherServlet Maven / Gradle / Ivy
Show all versions of aem-sdk-api Show documentation
/*
* Copyright 1997-2009 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.cq.commons.servlets;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.OptingServlet;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* {@linkplain NonExistingDispatcherServlet} is a solution to dispatch the
* sling:nonexisting resource type based on dynamic acceptance. With standard
* Sling it is only possible to register a single servlet for each HTTP method
* on the nonexisting resource.
*
*
* Please note: This is a temporary solution until Sling provides
* a built-in mechanism for this use case. Not to be used by client
* implementations!
*/
@SuppressWarnings("serial")
@SlingServlet(
paths = {
"/apps/sling/nonexisting/GET.servlet",
"/apps/sling/nonexisting/POST.servlet",
"/apps/sling/nonexisting/PUT.servlet"
}
)
@Reference(
name = "Servlet",
referenceInterface = NonExistingResourceServlet.class,
policy = ReferencePolicy.DYNAMIC,
cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE
)
public class NonExistingDispatcherServlet extends GenericServlet implements OptingServlet {
private final Logger log = LoggerFactory.getLogger(NonExistingDispatcherServlet.class);
private ComponentContext context;
private List unhandledServlets = new ArrayList();
private SortedMap servlets =
new TreeMap(new Comparator() {
/**
* Implementation following the latest OSGi R4 4.1 release:
* http://www.osgi.org/javadoc/r4v41/org/osgi/framework/ServiceReference.html#compareTo(java.lang.Object)
*
* This custom implementation is required because Sling does
* not yet use a 4.1 OSGi framework implementation.
*/
public int compare(ServiceReference ref1, ServiceReference ref2) {
// first check for equal references
long id1 = getServiceID(ref1);
long id2 = getServiceID(ref2);
if (id1 == id2) {
return 0;
}
int rank1 = getServiceRanking(ref1);
int rank2 = getServiceRanking(ref2);
if (rank1 == rank2) {
return (int) (id1 - id2);
} else {
return rank2 - rank1;
}
}
});
private static final String SERVLET_REQUEST_ATTR = NonExistingResourceServlet.class.getName();
public boolean accepts(SlingHttpServletRequest request) {
NonExistingResourceServlet servlet = findServlet(request);
if (servlet != null) {
// store servlet in request attribute to avoid that doGet(),
// doPost(), etc. have to call findServlet() again
request.setAttribute(SERVLET_REQUEST_ATTR, servlet);
request.getRequestProgressTracker().log("{0}: will dispatch to {1}", this.getClass().getSimpleName(), servlet.getClass().getName());
return true;
}
request.getRequestProgressTracker().log("{0}: no servlet found");
return false;
}
@Override
public void service(ServletRequest request, ServletResponse res)
throws ServletException, IOException {
SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
NonExistingResourceServlet servlet = (NonExistingResourceServlet)
request.getAttribute(SERVLET_REQUEST_ATTR);
if (servlet != null) {
slingRequest.getRequestProgressTracker().startTimer(servlet.getClass().getName());
servlet.service(request, res);
slingRequest.getRequestProgressTracker().logTimer(servlet.getClass().getName());
} else {
// rare case - have to search again
servlet = findServlet(slingRequest);
if (servlet != null) {
slingRequest.getRequestProgressTracker().log("{0}: will dispatch to {1}", this.getClass().getSimpleName(), servlet.getClass().getName());
slingRequest.getRequestProgressTracker().startTimer(servlet.getClass().getName());
servlet.service(request, res);
slingRequest.getRequestProgressTracker().logTimer(servlet.getClass().getName());
} else {
slingRequest.getRequestProgressTracker().log("{0}: no servlet found");
SlingHttpServletResponse response = (SlingHttpServletResponse) res;
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"No " + NonExistingResourceServlet.class.getName() + " found for handling " +
"sling:nonexisting case (and no OptingServlet support)");
}
}
}
// ----------------------------------------------< servlet selection >
protected NonExistingResourceServlet findServlet(SlingHttpServletRequest request) {
synchronized (servlets) {
// this iteration is sorted by rank, descending
for (NonExistingResourceServlet servlet : servlets.values()) {
if (servlet.accepts(request)) {
return servlet;
}
}
}
return null;
}
// ----------------------------------------------< osgi handling >
protected void activate(ComponentContext context) {
synchronized (servlets) {
this.context = context;
for (ServiceReference reference : unhandledServlets) {
registerServlet(reference);
}
unhandledServlets.clear();
}
}
protected void deactivate(ComponentContext context) {
synchronized (servlets) {
this.context = null;
}
}
protected void bindServlet(ServiceReference reference) {
synchronized (servlets) {
if (context == null) {
unhandledServlets.add(reference);
} else {
registerServlet(reference);
}
}
}
protected void unbindServlet(ServiceReference reference) {
synchronized (servlets) {
unregisterServlet(reference);
unhandledServlets.remove(reference);
}
}
private void registerServlet(ServiceReference reference) {
NonExistingResourceServlet servlet = (NonExistingResourceServlet)
context.locateService("Servlet", reference);
if ( servlet != null ) {
synchronized (servlets) {
servlets.put(reference, servlet);
log.info("Servlets in order: " + servlets.values().toString());
}
}
}
private void unregisterServlet(ServiceReference reference) {
synchronized (servlets) {
servlets.remove(reference);
}
}
private long getServiceID(ServiceReference reference) {
return (Long) reference.getProperty(Constants.SERVICE_ID);
}
private int getServiceRanking(ServiceReference reference) {
Object obj = reference.getProperty(Constants.SERVICE_RANKING);
if (obj == null) {
// default service.ranking value
return 0;
} else if (obj instanceof Integer) {
return (Integer) obj;
} else {
log.warn("Component " + reference.getProperty("component.name") +
" has a non-Integer '" + Constants.SERVICE_RANKING + "' property");
return 0;
}
}
}