You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by en...@apache.org on 2018/08/19 20:38:48 UTC

[sling-org-apache-sling-jcr-jackrabbit-accessmanager] branch master updated: SLING-7831 support injecting custom/alternate PostResponse implementations for the servlets in the usermanager and accessmanager bundles

This is an automated email from the ASF dual-hosted git repository.

enorman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-jackrabbit-accessmanager.git


The following commit(s) were added to refs/heads/master by this push:
     new c2d5995  SLING-7831 support injecting custom/alternate PostResponse implementations for the servlets in the usermanager and accessmanager bundles
c2d5995 is described below

commit c2d5995ed48ae20bfd86bef22f44c786b758b44a
Author: Eric Norman <en...@apache.org>
AuthorDate: Sun Aug 19 13:38:40 2018 -0700

    SLING-7831 support injecting custom/alternate PostResponse
    implementations for the servlets in the usermanager and accessmanager
    bundles
---
 pom.xml                                            |   3 +
 .../post/AbstractAccessPostServlet.java            | 166 ++++++++++++++++++++-
 .../accessmanager/post/AbstractGetAclServlet.java  |   6 -
 .../accessmanager/post/DeleteAcesServlet.java      |  33 +++-
 .../accessmanager/post/ModifyAceServlet.java       |  32 +++-
 .../accessmanager/post/package-info.java           |   2 +-
 6 files changed, 221 insertions(+), 21 deletions(-)

diff --git a/pom.xml b/pom.xml
index d0cdb61..8da4c32 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,6 +49,9 @@
                 <extensions>true</extensions>
                 <configuration>
                     <instructions>
+                        <Embed-Dependency>
+                            org.apache.sling.servlets.post;inline="org/apache/sling/servlets/post/impl/helper/MediaRangeList*"
+                        </Embed-Dependency>
                     </instructions>
                 </configuration>
             </plugin>
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractAccessPostServlet.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractAccessPostServlet.java
index 0044688..2887921 100644
--- a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractAccessPostServlet.java
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractAccessPostServlet.java
@@ -18,7 +18,9 @@ package org.apache.sling.jcr.jackrabbit.accessmanager.post;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
@@ -34,13 +36,17 @@ import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.SlingHttpServletResponse;
 import org.apache.sling.api.resource.ResourceNotFoundException;
 import org.apache.sling.api.resource.ResourceUtil;
-import org.apache.sling.servlets.post.HtmlResponse;
 import org.apache.sling.api.servlets.SlingAllMethodsServlet;
 import org.apache.sling.api.wrappers.SlingRequestPaths;
 import org.apache.sling.servlets.post.AbstractPostResponse;
+import org.apache.sling.servlets.post.HtmlResponse;
+import org.apache.sling.servlets.post.JSONResponse;
 import org.apache.sling.servlets.post.Modification;
+import org.apache.sling.servlets.post.PostResponse;
+import org.apache.sling.servlets.post.PostResponseCreator;
 import org.apache.sling.servlets.post.SlingPostConstants;
-import org.apache.sling.servlets.post.JSONResponse;
+import org.apache.sling.servlets.post.impl.helper.MediaRangeList;
+import org.osgi.framework.Constants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -55,6 +61,13 @@ public abstract class AbstractAccessPostServlet extends SlingAllMethodsServlet {
      */
     private final Logger log = LoggerFactory.getLogger(getClass());
 
+    /** Sorted list of post response creator holders. */
+    private final List<PostResponseCreatorHolder> postResponseCreators = new ArrayList<>();
+
+    /** Cached array of post response creators used during request processing. */
+    private PostResponseCreator[] cachedPostResponseCreators = new PostResponseCreator[0];
+
+
 	/* (non-Javadoc)
 	 * @see org.apache.sling.api.servlets.SlingAllMethodsServlet#doPost(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.SlingHttpServletResponse)
 	 */
@@ -63,7 +76,7 @@ public abstract class AbstractAccessPostServlet extends SlingAllMethodsServlet {
 			SlingHttpServletResponse httpResponse) throws ServletException,
 			IOException {
         // prepare the response
-		AbstractPostResponse response = createHtmlResponse(request);
+    	PostResponse response = createPostResponse(request);
         response.setReferer(request.getHeader("referer"));
 
         // calculate the paths
@@ -145,13 +158,53 @@ public abstract class AbstractAccessPostServlet extends SlingAllMethodsServlet {
      *   <li>the response content type is application/json
      * </ul>
      * or a {@link org.apache.sling.api.servlets.HtmlResponse} otherwise
+     * @deprecated use {@link #createPostResponse(SlingHttpServletRequest)} instead
      */
+	@Deprecated
     protected AbstractPostResponse createHtmlResponse(SlingHttpServletRequest req) {
-    	if (JSONResponse.RESPONSE_CONTENT_TYPE.equals(req.getResponseContentType())) {
-    		return new JSONResponse();
-    	} else {
+    	return (AbstractPostResponse)createPostResponse(req);
+    }
+	
+    /**
+     * Creates an instance of a PostResponse.
+     * @param req The request being serviced
+     * @return a {@link org.apache.sling.servlets.post.impl.helper.JSONResponse} if any of these conditions are true:
+     * <ul>
+     *   <li> the request has an <code>Accept</code> header of <code>application/json</code></li>
+     *   <li>the request is a JSON POST request (see SLING-1172)</li>
+     *   <li>the request has a request parameter <code>:accept=application/json</code></li>
+     * </ul>
+     * or a {@link org.apache.sling.api.servlets.PostResponse} otherwise
+     */
+    PostResponse createPostResponse(final SlingHttpServletRequest req) {
+        for (final PostResponseCreator creator : cachedPostResponseCreators) {
+            final PostResponse response = creator.createPostResponse(req);
+            if (response != null) {
+                return response;
+            }
+        }
+
+        //for backward compatibility, if no "accept" request param or header is supplied
+        // then prefer the SlingHttpServletRequest#getResponseContentType value
+        MediaRangeList mediaRangeList = null;
+        String queryParam = req.getParameter(MediaRangeList.PARAM_ACCEPT);
+        if (queryParam == null || queryParam.trim().length() == 0) {
+        	String headerValue = req.getHeader(MediaRangeList.HEADER_ACCEPT);
+        	if (headerValue == null || headerValue.trim().length() == 0) {
+        		//no param or header supplied, so try the response content type
+        		mediaRangeList = new MediaRangeList(req.getResponseContentType());
+        	}
+        }
+
+        // Fall through to default behavior
+        if (mediaRangeList == null) {
+        	mediaRangeList = new MediaRangeList(req);
+        }
+        if (JSONResponse.RESPONSE_CONTENT_TYPE.equals(mediaRangeList.prefer("text/html", JSONResponse.RESPONSE_CONTENT_TYPE))) {
+            return new JSONResponse();
+        } else {
             return new HtmlResponse();
-    	}
+        }
     }
 	
 	/**
@@ -160,9 +213,24 @@ public abstract class AbstractAccessPostServlet extends SlingAllMethodsServlet {
 	 * @param request the sling http request to process
 	 * @param response the response
 	 * @param changes
+	 * 
+	 * @deprecated use {@link #handleOperation(SlingHttpServletRequest, PostResponse, List)} instead
+	 */
+    @Deprecated
+	protected void handleOperation(SlingHttpServletRequest request,
+			AbstractPostResponse response, List<Modification> changes) throws RepositoryException {
+		handleOperation(request, (PostResponse)response, changes);
+	}
+    
+	/**
+	 * Extending Servlet should implement this operation to do the work
+	 *
+	 * @param request the sling http request to process
+	 * @param response the response
+	 * @param changes
 	 */
 	abstract protected void handleOperation(SlingHttpServletRequest request,
-			AbstractPostResponse response, List<Modification> changes) throws RepositoryException;
+			PostResponse response, List<Modification> changes) throws RepositoryException;
 
 
     /**
@@ -170,8 +238,20 @@ public abstract class AbstractAccessPostServlet extends SlingAllMethodsServlet {
      *
      * @param ctx the post processor
      * @return the redirect location or <code>null</code>
+     * @deprecated use {@link #getRedirectUrl(HttpServletRequest, PostResponse)} instead
      */
+	@Deprecated
     protected String getRedirectUrl(HttpServletRequest request, AbstractPostResponse ctx) {
+    	return getRedirectUrl(request, (PostResponse)ctx);
+    }
+    
+    /**
+     * compute redirect URL (SLING-126)
+     *
+     * @param ctx the post processor
+     * @return the redirect location or <code>null</code>
+     */
+    protected String getRedirectUrl(HttpServletRequest request, PostResponse ctx) {
         // redirect param has priority (but see below, magic star)
         String result = request.getParameter(SlingPostConstants.RP_REDIRECT_TO);
         if (result != null && ctx.getPath() != null) {
@@ -321,4 +401,74 @@ public abstract class AbstractAccessPostServlet extends SlingAllMethodsServlet {
                 + resourcePath);
 
     }
+
+
+    /**
+     * Bind a new post response creator
+     */
+	// NOTE: the @Reference annotation is not inherited, so subclasses will need to override the #bindPostResponseCreator 
+	// and #unbindPostResponseCreator methods to provide the @Reference annotation.     
+	//
+	// @Reference(service = PostResponseCreator.class,
+	//         cardinality = ReferenceCardinality.MULTIPLE,
+	//         policy = ReferencePolicy.DYNAMIC)
+    protected void bindPostResponseCreator(final PostResponseCreator creator, final Map<String, Object> properties) {
+        final PostResponseCreatorHolder nngh = new PostResponseCreatorHolder();
+        nngh.creator = creator;
+        nngh.ranking = getRanking(properties);
+
+        synchronized ( this.postResponseCreators ) {
+            int index = 0;
+            while ( index < this.postResponseCreators.size() &&
+                    nngh.ranking < this.postResponseCreators.get(index).ranking ) {
+                index++;
+            }
+            if ( index == this.postResponseCreators.size() ) {
+                this.postResponseCreators.add(nngh);
+            } else {
+                this.postResponseCreators.add(index, nngh);
+            }
+            this.updatePostResponseCreatorCache();
+        }
+    }
+
+    /**
+     * Unbind a post response creator
+     */
+    protected void unbindPostResponseCreator(final PostResponseCreator creator, final Map<String, Object> properties) {
+        synchronized ( this.postResponseCreators ) {
+            final Iterator<PostResponseCreatorHolder> i = this.postResponseCreators.iterator();
+            while ( i.hasNext() ) {
+                final PostResponseCreatorHolder current = i.next();
+                if ( current.creator == creator ) {
+                    i.remove();
+                }
+            }
+            this.updatePostResponseCreatorCache();
+        }
+    }
+
+    /**
+     * Update the post response creator cache
+     * This method is called by sync'ed methods, no need to add additional syncing.
+     */
+    private void updatePostResponseCreatorCache() {
+        final PostResponseCreator[] localCache = new PostResponseCreator[this.postResponseCreators.size()];
+        int index = 0;
+        for(final PostResponseCreatorHolder current : this.postResponseCreators) {
+            localCache[index] = current.creator;
+            index++;
+        }
+        this.cachedPostResponseCreators = localCache;
+    }
+    
+    private int getRanking(final Map<String, Object> properties) {
+        final Object val = properties.get(Constants.SERVICE_RANKING);
+        return val instanceof Integer ? (Integer)val : 0;
+    }
+    
+    private static final class PostResponseCreatorHolder {
+        public PostResponseCreator creator;
+        public int ranking;
+    }    
 }
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractGetAclServlet.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractGetAclServlet.java
index b56adf3..9ee88f6 100644
--- a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractGetAclServlet.java
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractGetAclServlet.java
@@ -19,9 +19,7 @@ package org.apache.sling.jcr.jackrabbit.accessmanager.post;
 import java.io.IOException;
 import java.security.Principal;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -31,18 +29,14 @@ import java.util.Set;
 
 import javax.jcr.AccessDeniedException;
 import javax.jcr.Item;
-import javax.jcr.PathNotFoundException;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
-import javax.jcr.UnsupportedRepositoryOperationException;
 import javax.jcr.security.AccessControlEntry;
-import javax.jcr.security.AccessControlManager;
 import javax.jcr.security.Privilege;
 import javax.json.Json;
 import javax.json.JsonArrayBuilder;
 import javax.json.JsonObject;
 import javax.json.JsonObjectBuilder;
-import javax.json.JsonValue;
 import javax.json.stream.JsonGenerator;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletResponse;
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/DeleteAcesServlet.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/DeleteAcesServlet.java
index a676276..da8e3ec 100644
--- a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/DeleteAcesServlet.java
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/DeleteAcesServlet.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import javax.jcr.Item;
@@ -34,10 +35,14 @@ import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.ResourceNotFoundException;
 import org.apache.sling.jcr.base.util.AccessControlUtil;
 import org.apache.sling.jcr.jackrabbit.accessmanager.DeleteAces;
-import org.apache.sling.servlets.post.AbstractPostResponse;
 import org.apache.sling.servlets.post.Modification;
+import org.apache.sling.servlets.post.PostResponse;
+import org.apache.sling.servlets.post.PostResponseCreator;
 import org.apache.sling.servlets.post.SlingPostConstants;
 import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
 
 /**
  * <p>
@@ -80,12 +85,34 @@ import org.osgi.service.component.annotations.Component;
 public class DeleteAcesServlet extends AbstractAccessPostServlet implements DeleteAces {
 	private static final long serialVersionUID = 3784866802938282971L;
 
+    /**
+     * Overridden since the @Reference annotation is not inherited from the super method
+     *  
+	 * @see org.apache.sling.jackrabbit.usermanager.impl.post.AbstractPostServlet#bindPostResponseCreator(org.apache.sling.servlets.post.PostResponseCreator, java.util.Map)
+	 */
+	@Override
+    @Reference(service = PostResponseCreator.class,
+	    cardinality = ReferenceCardinality.MULTIPLE,
+	    policy = ReferencePolicy.DYNAMIC)
+	protected void bindPostResponseCreator(PostResponseCreator creator, Map<String, Object> properties) {
+		super.bindPostResponseCreator(creator, properties);
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.apache.sling.jackrabbit.usermanager.impl.post.AbstractPostServlet#unbindPostResponseCreator(org.apache.sling.servlets.post.PostResponseCreator, java.util.Map)
+	 */
+	@Override
+	protected void unbindPostResponseCreator(PostResponseCreator creator, Map<String, Object> properties) {
+		super.unbindPostResponseCreator(creator, properties);
+	}
+    
+	
 	/* (non-Javadoc)
-	 * @see org.apache.sling.jackrabbit.accessmanager.post.AbstractAccessPostServlet#handleOperation(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
+	 * @see org.apache.sling.jackrabbit.accessmanager.post.AbstractAccessPostServlet#handleOperation(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.servlets.post.PostResponse, java.util.List)
 	 */
 	@Override
 	protected void handleOperation(SlingHttpServletRequest request,
-			AbstractPostResponse htmlResponse, List<Modification> changes)
+			PostResponse htmlResponse, List<Modification> changes)
 			throws RepositoryException {
 
 		Session session = request.getResourceResolver().adaptTo(Session.class);
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java
index 8647cf9..c11f85c 100644
--- a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java
@@ -35,9 +35,13 @@ import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.ResourceNotFoundException;
 import org.apache.sling.jcr.base.util.AccessControlUtil;
 import org.apache.sling.jcr.jackrabbit.accessmanager.ModifyAce;
-import org.apache.sling.servlets.post.AbstractPostResponse;
 import org.apache.sling.servlets.post.Modification;
+import org.apache.sling.servlets.post.PostResponse;
+import org.apache.sling.servlets.post.PostResponseCreator;
 import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
 
 /**
  * <p>
@@ -90,12 +94,34 @@ property= {
 public class ModifyAceServlet extends AbstractAccessPostServlet implements ModifyAce {
 	private static final long serialVersionUID = -9182485466670280437L;
 
+    /**
+     * Overridden since the @Reference annotation is not inherited from the super method
+     *  
+	 * @see org.apache.sling.jackrabbit.usermanager.impl.post.AbstractPostServlet#bindPostResponseCreator(org.apache.sling.servlets.post.PostResponseCreator, java.util.Map)
+	 */
+	@Override
+    @Reference(service = PostResponseCreator.class,
+	    cardinality = ReferenceCardinality.MULTIPLE,
+	    policy = ReferencePolicy.DYNAMIC)
+	protected void bindPostResponseCreator(PostResponseCreator creator, Map<String, Object> properties) {
+		super.bindPostResponseCreator(creator, properties);
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.apache.sling.jackrabbit.usermanager.impl.post.AbstractPostServlet#unbindPostResponseCreator(org.apache.sling.servlets.post.PostResponseCreator, java.util.Map)
+	 */
+	@Override
+	protected void unbindPostResponseCreator(PostResponseCreator creator, Map<String, Object> properties) {
+		super.unbindPostResponseCreator(creator, properties);
+	}
+    
+	
 	/* (non-Javadoc)
-	 * @see org.apache.sling.jackrabbit.accessmanager.post.AbstractAccessPostServlet#handleOperation(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
+	 * @see org.apache.sling.jackrabbit.accessmanager.post.AbstractAccessPostServlet#handleOperation(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.servlets.post.PostResponse, java.util.List)
 	 */
 	@Override
 	protected void handleOperation(SlingHttpServletRequest request,
-			AbstractPostResponse response, List<Modification> changes)
+			PostResponse response, List<Modification> changes)
 			throws RepositoryException {
 		Session session = request.getResourceResolver().adaptTo(Session.class);
     	String resourcePath = request.getResource().getPath();
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/package-info.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/package-info.java
index 708b13c..79406f4 100644
--- a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/package-info.java
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/package-info.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-@org.osgi.annotation.versioning.Version("3.0.1")
+@org.osgi.annotation.versioning.Version("3.1.0")
 package org.apache.sling.jcr.jackrabbit.accessmanager.post;