Java tutorial
/* * #%L * ACS AEM Commons Bundle * %% * Copyright (C) 2017 Adobe * %% * Licensed 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. * #L% */ package com.adobe.acs.commons.dam.impl; import org.apache.commons.lang3.StringUtils; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.ConfigurationPolicy; import org.apache.felix.scr.annotations.Properties; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Service; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ValueMap; import org.apache.sling.api.servlets.SlingSafeMethodsServlet; import org.apache.sling.api.wrappers.CompositeValueMap; import org.apache.sling.api.wrappers.SlingHttpServletRequestWrapper; import org.apache.sling.api.wrappers.ValueMapDecorator; import org.apache.sling.jcr.resource.JcrResourceConstants; import org.apache.sling.servlets.post.AbstractPostResponse; import org.apache.sling.servlets.post.Modification; import org.apache.sling.servlets.post.PostOperation; import org.apache.sling.servlets.post.SlingPostProcessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.HashMap; import java.util.List; @Component(label = "ACS AEM Commons - Assets Folder Properties Support", policy = ConfigurationPolicy.REQUIRE, immediate = true) @Properties({ @Property(name = "service.ranking", intValue = -2000, propertyPrivate = true), @Property(name = "sling.filter.scope", value = "REQUEST", propertyPrivate = true), @Property(name = "sling.filter.pattern", value = "/content/dam/.*", propertyPrivate = true), @Property(name = "sling.servlet.methods", value = "GET", propertyPrivate = true), @Property(name = "sling.servlet.resourceTypes", value = "acs-commons/touchui-widgets/asset-folder-properties-support", propertyPrivate = true) }) @Service public class AssetsFolderPropertiesSupport extends SlingSafeMethodsServlet implements Filter, SlingPostProcessor { private static final Logger log = LoggerFactory.getLogger(AssetsFolderPropertiesSupport.class); private static final String DAM_PATH_PREFIX = "/content/dam"; private static final String POST_METHOD = "post"; private static final String OPERATION = ":operation"; private static final String DAM_FOLDER_SHARE_OPERATION = "dam.share.folder"; private static final String GRANITE_UI_FORM_VALUES = "granite.ui.form.values"; /** * The is a reference to the OOTB AEM PostOperation that handles updates for Folder Properties; This is used below in process(..) to ensure that all OOTB behaviors are executed. */ @Reference(target = "&(sling.post.operation=dam.share.folder)(sling.servlet.methods=POST)") private PostOperation folderShareHandler; /** * This method is responsible for post processing POSTs to the FolderShareHandler PostOperation (:operation = dam.share.folder). * This method will store a whitelisted set of request parameters to their relative location off of the [sling:*Folder] node. * * Note, this is executed AFTER the OOTB FolderShareHandler PostOperation. * * At this time this method only supports single-value Strings and ignores all @typeHints. * * This method must fail fast via the accepts(...) method. * * @param servletRequest the request object * @param servletResponse the response object * @param chain the filter chain * @throws IOException * @throws ServletException */ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { final SlingHttpServletRequest request = (SlingHttpServletRequest) servletRequest; final SlingHttpServletResponse response = (SlingHttpServletResponse) servletResponse; if (!accepts(request)) { chain.doFilter(request, response); return; } log.trace("ACS AEM Commons Assets Folder Properties Support applied to POST Request"); chain.doFilter(new AssetsFolderPropertiesSupportRequest(request, null), response); } public void init(FilterConfig filterConfig) throws ServletException { // Do Nothing } public void destroy() { // Do Nothing } public void process(SlingHttpServletRequest request, List<Modification> changes) throws Exception { if (AssetsFolderPropertiesSupportRequest.isMarked(request)) { log.trace( "Sending the the wrapped dam.folder.share request to the AEM Assets dam.folder.share PostOperation for final processing"); final AssetsFolderPropertiesSupportRequest wrappedRequest = new AssetsFolderPropertiesSupportRequest( request, DAM_FOLDER_SHARE_OPERATION); folderShareHandler.run(wrappedRequest, new DummyPostResponse(), new SlingPostProcessor[] {}); log.trace( "Processed the the wrapped dam.folder.share request with the AEM Assets dam.folder.share PostOperation"); } } /** * Gateway method the Filter uses to determine if the request is a candidate for processing by Assets Folder Properties Support. * These checks should be fast and fail broadest and fastest first. * * @param request the request * @return true if Assets Folder Properties Support should process this request. */ @SuppressWarnings("squid:S3923") protected boolean accepts(SlingHttpServletRequest request) { if (!StringUtils.equalsIgnoreCase(POST_METHOD, request.getMethod())) { // Only POST methods are processed return false; } else if (!DAM_FOLDER_SHARE_OPERATION.equals(request.getParameter(OPERATION))) { // Only requests with :operation=dam.share.folder are processed return false; } else if (!StringUtils.startsWith(request.getResource().getPath(), DAM_PATH_PREFIX)) { // Only requests under /content/dam are processed return false; } else if (!request.getResource().isResourceType(JcrResourceConstants.NT_SLING_FOLDER) && !request.getResource().isResourceType(JcrResourceConstants.NT_SLING_ORDERED_FOLDER)) { // Only requests to sling:Folders or sling:Ordered folders are processed return false; } // If the above checks do not fail, treat as a valid request return true; } /** * This method handles the READING of the properties so that granite UI widgets can display stored data in the form. * This needs to be included AFTER /apps/dam/gui/content/assets/foldersharewizard/jcr:content/body/items/form/items/wizard/items/settingStep/items/fixedColumns/items/fixedColumn2/items/tabs/items/tab1/items/folderproperties * such that it can augment the Property map constructed by that OOTB script. * * Note that this exposes a value map for the [sling:*Folder] node, and NOT the [sling:*Folder]/jcr:content, so properties must be prefixed with jcr:content/... * * This can be achieved by creating a resource merge: * /apps/dam/gui/content/assets/foldersharewizard/jcr:content/body/items/form/items/wizard/items/settingStep/items/fixedColumns/items/fixedColumn2/items/tabs/items/tab1/items/folderproperties/assets-folder-properties-support@sling:resourceType = acs-commons/touchui-widgets/asset-folder-properties-support * /apps/dam/gui/content/assets/foldersharewizard/jcr:content/body/items/form/items/wizard/items/settingStep/items/fixedColumns/items/fixedColumn2/items/tabs/items/tab1/items/folderproperties/assets-folder-properties-support@sling:orderBefore = titlefield * * @param request the request object * @param response the response object * @throws ServletException * @throws IOException */ @Override protected final void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { final Resource suffixResource = request.getResourceResolver() .resolve(request.getRequestPathInfo().getSuffix()); if (suffixResource == null) { return; } log.trace("AssetsFolderPropertiesSupport GET method for folder resource [ {} ]", suffixResource.getPath()); ValueMap formProperties = (ValueMap) request.getAttribute(GRANITE_UI_FORM_VALUES); if (formProperties == null) { formProperties = new ValueMapDecorator(new HashMap<String, Object>()); } request.setAttribute(GRANITE_UI_FORM_VALUES, new CompositeValueMap(formProperties, suffixResource.getValueMap(), true)); } /** Synthetic Objects to allow this request to traverse the request processing stack **/ protected class DummyPostResponse extends AbstractPostResponse { protected void doSend(HttpServletResponse response) throws IOException { // Do nothing } public void onChange(String type, String... arguments) { // Do nothing } } /** * Sling HTTP Request wrapper that masks the :operation so the default Sling POST Servlet can be invoked. */ protected static class AssetsFolderPropertiesSupportRequest extends SlingHttpServletRequestWrapper { private static String REQUEST_ATTR_KEY = AssetsFolderPropertiesSupportRequest.class.getName(); private String operationValue; public AssetsFolderPropertiesSupportRequest(SlingHttpServletRequest request, String operationValue) { super(request); markRequest(request); this.operationValue = operationValue; } public static void markRequest(SlingHttpServletRequest request) { request.setAttribute(REQUEST_ATTR_KEY, true); } protected static boolean isMarked(SlingHttpServletRequest request) { return request.getAttribute(REQUEST_ATTR_KEY) != null; } public String getParameter(String key) { if (isMarked(this) && OPERATION.equals(key)) { return operationValue; } else { return super.getParameter(key); } } } }