| /* |
| * 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.jackrabbit.usermanager.impl.post; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import javax.jcr.RepositoryException; |
| import javax.jcr.Session; |
| import javax.servlet.ServletException; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| |
| 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.api.servlets.HtmlResponse; |
| import org.apache.sling.api.servlets.SlingAllMethodsServlet; |
| import org.apache.sling.api.wrappers.SlingRequestPaths; |
| import org.apache.sling.servlets.post.Modification; |
| import org.apache.sling.servlets.post.SlingPostConstants; |
| import org.apache.sling.servlets.post.impl.helper.JSONResponse; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * Base class for all the POST servlets for the UserManager operations |
| */ |
| public abstract class AbstractPostServlet extends |
| SlingAllMethodsServlet { |
| |
| private static final long serialVersionUID = 7408267654653472120L; |
| |
| /** |
| * default log |
| */ |
| private final Logger log = LoggerFactory.getLogger(getClass()); |
| |
| /* |
| * (non-Javadoc) |
| * @see |
| * org.apache.sling.api.servlets.SlingAllMethodsServlet#doPost(org.apache |
| * .sling.api.SlingHttpServletRequest, |
| * org.apache.sling.api.SlingHttpServletResponse) |
| */ |
| @Override |
| protected void doPost(SlingHttpServletRequest request, |
| SlingHttpServletResponse httpResponse) throws ServletException, |
| IOException { |
| // prepare the response |
| HtmlResponse htmlResponse = createHtmlResponse(request); |
| htmlResponse.setReferer(request.getHeader("referer")); |
| |
| // calculate the paths |
| String path = getItemPath(request); |
| htmlResponse.setPath(path); |
| |
| // location |
| htmlResponse.setLocation(externalizePath(request, path)); |
| |
| // parent location |
| path = ResourceUtil.getParent(path); |
| if (path != null) { |
| htmlResponse.setParentLocation(externalizePath(request, path)); |
| } |
| |
| Session session = request.getResourceResolver().adaptTo(Session.class); |
| |
| final List<Modification> changes = new ArrayList<Modification>(); |
| |
| try { |
| handleOperation(request, htmlResponse, changes); |
| |
| // TODO: maybe handle SlingAuthorizablePostProcessor handlers here |
| |
| // set changes on html response |
| for (Modification change : changes) { |
| switch (change.getType()) { |
| case MODIFY: |
| htmlResponse.onModified(change.getSource()); |
| break; |
| case DELETE: |
| htmlResponse.onDeleted(change.getSource()); |
| break; |
| case MOVE: |
| htmlResponse.onMoved(change.getSource(), |
| change.getDestination()); |
| break; |
| case COPY: |
| htmlResponse.onCopied(change.getSource(), |
| change.getDestination()); |
| break; |
| case CREATE: |
| htmlResponse.onCreated(change.getSource()); |
| break; |
| case ORDER: |
| htmlResponse.onChange("ordered", change.getSource(), |
| change.getDestination()); |
| break; |
| } |
| } |
| |
| if (session.hasPendingChanges()) { |
| session.save(); |
| } |
| } catch (ResourceNotFoundException rnfe) { |
| htmlResponse.setStatus(HttpServletResponse.SC_NOT_FOUND, |
| rnfe.getMessage()); |
| } catch (Throwable throwable) { |
| log.debug("Exception while handling POST " |
| + request.getResource().getPath() + " with " |
| + getClass().getName(), throwable); |
| htmlResponse.setError(throwable); |
| } finally { |
| try { |
| if (session.hasPendingChanges()) { |
| session.refresh(false); |
| } |
| } catch (RepositoryException e) { |
| log.warn("RepositoryException in finally block: {}", |
| e.getMessage(), e); |
| } |
| } |
| |
| // check for redirect URL if processing succeeded |
| if (htmlResponse.isSuccessful()) { |
| String redirect = getRedirectUrl(request, htmlResponse); |
| if (redirect != null) { |
| httpResponse.sendRedirect(redirect); |
| return; |
| } |
| } |
| |
| // create a html response and send if unsuccessful or no redirect |
| htmlResponse.send(httpResponse, isSetStatus(request)); |
| } |
| |
| /** |
| * Creates an instance of a HtmlResponse. |
| * @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 response content type is application/json |
| * </ul> |
| * or a {@link org.apache.sling.api.servlets.HtmlResponse} otherwise |
| */ |
| protected HtmlResponse createHtmlResponse(SlingHttpServletRequest req) { |
| if (JSONResponse.RESPONSE_CONTENT_TYPE.equals(req.getResponseContentType())) { |
| return new JSONResponse(); |
| } else { |
| return new HtmlResponse(); |
| } |
| } |
| |
| /** |
| * Extending Servlet should implement this operation to do the work |
| * |
| * @param request the sling http request to process |
| * @param htmlResponse the response |
| * @param changes |
| */ |
| abstract protected void handleOperation(SlingHttpServletRequest request, |
| HtmlResponse htmlResponse, List<Modification> changes) |
| throws RepositoryException; |
| |
| /** |
| * compute redirect URL (SLING-126) |
| * |
| * @param ctx the post processor |
| * @return the redirect location or <code>null</code> |
| */ |
| protected String getRedirectUrl(HttpServletRequest request, HtmlResponse ctx) { |
| // redirect param has priority (but see below, magic star) |
| String result = request.getParameter(SlingPostConstants.RP_REDIRECT_TO); |
| if (result != null && ctx.getPath() != null) { |
| |
| // redirect to created/modified Resource |
| int star = result.indexOf('*'); |
| if (star >= 0) { |
| StringBuffer buf = new StringBuffer(); |
| |
| // anything before the star |
| if (star > 0) { |
| buf.append(result.substring(0, star)); |
| } |
| |
| // append the name of the manipulated node |
| buf.append(ResourceUtil.getName(ctx.getPath())); |
| |
| // anything after the star |
| if (star < result.length() - 1) { |
| buf.append(result.substring(star + 1)); |
| } |
| |
| // use the created path as the redirect result |
| result = buf.toString(); |
| |
| } else if (result.endsWith(SlingPostConstants.DEFAULT_CREATE_SUFFIX)) { |
| // if the redirect has a trailing slash, append modified node |
| // name |
| result = result.concat(ResourceUtil.getName(ctx.getPath())); |
| } |
| |
| if (log.isDebugEnabled()) { |
| log.debug("Will redirect to " + result); |
| } |
| } |
| return result; |
| } |
| |
| protected boolean isSetStatus(SlingHttpServletRequest request) { |
| String statusParam = request.getParameter(SlingPostConstants.RP_STATUS); |
| if (statusParam == null) { |
| log.debug( |
| "getStatusMode: Parameter {} not set, assuming standard status code", |
| SlingPostConstants.RP_STATUS); |
| return true; |
| } |
| |
| if (SlingPostConstants.STATUS_VALUE_BROWSER.equals(statusParam)) { |
| log.debug( |
| "getStatusMode: Parameter {} asks for user-friendly status code", |
| SlingPostConstants.RP_STATUS); |
| return false; |
| } |
| |
| if (SlingPostConstants.STATUS_VALUE_STANDARD.equals(statusParam)) { |
| log.debug( |
| "getStatusMode: Parameter {} asks for standard status code", |
| SlingPostConstants.RP_STATUS); |
| return true; |
| } |
| |
| log.debug( |
| "getStatusMode: Parameter {} set to unknown value {}, assuming standard status code", |
| SlingPostConstants.RP_STATUS); |
| return true; |
| } |
| |
| // ------ These methods were copied from AbstractSlingPostOperation ------ |
| |
| /** |
| * Returns the path of the resource of the request as the item path. |
| * <p> |
| * This method may be overwritten by extension if the operation has |
| * different requirements on path processing. |
| */ |
| protected String getItemPath(SlingHttpServletRequest request) { |
| return request.getResource().getPath(); |
| } |
| |
| /** |
| * Returns an external form of the given path prepending the context path |
| * and appending a display extension. |
| * |
| * @param path the path to externalize |
| * @return the url |
| */ |
| protected final String externalizePath(SlingHttpServletRequest request, |
| String path) { |
| StringBuffer ret = new StringBuffer(); |
| ret.append(SlingRequestPaths.getContextPath(request)); |
| ret.append(request.getResourceResolver().map(path)); |
| |
| // append optional extension |
| String ext = request.getParameter(SlingPostConstants.RP_DISPLAY_EXTENSION); |
| if (ext != null && ext.length() > 0) { |
| if (ext.charAt(0) != '.') { |
| ret.append('.'); |
| } |
| ret.append(ext); |
| } |
| |
| return ret.toString(); |
| } |
| |
| } |