All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.aemds.guide.servlet.GuideSubmitServlet Maven / Gradle / Ivy

/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2014 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 **************************************************************************/

package com.adobe.aemds.guide.servlet;

import com.adobe.aem.transaction.core.exception.TransactionException;
import com.adobe.aemds.guide.common.AEMForm;
import com.adobe.aemds.guide.common.GuideError;
import com.adobe.aemds.guide.common.GuideValidationResult;
import com.adobe.aemds.guide.model.FormSubmitInfo;
import com.adobe.aemds.guide.model.SignAgreementInfo;
import com.adobe.aemds.guide.model.SubmitType;
import com.adobe.aemds.guide.model.ValidationOptions;
import com.adobe.aemds.guide.service.*;
import com.adobe.aemds.guide.service.external.FormPortalSubmitPreprocessor;
import com.adobe.aemds.guide.service.external.PortalRecordInfo;
import com.adobe.aemds.guide.service.external.GuideSubmitPostProcessor;
import com.adobe.aemds.guide.submitutils.FileRequestParameter;
import com.adobe.aemds.guide.submitutils.FormFieldRequestParameter;
import com.adobe.aemds.guide.utils.*;
import com.adobe.forms.common.service.FileAttachmentWrapper;
import com.adobe.forms.common.submitutils.CustomParameterRequest;
import com.adobe.forms.common.submitutils.CustomResponse;
import com.adobe.forms.common.submitutils.ParameterMap;
import com.adobe.aem.transaction.core.FormsTransactionConstants;
import com.adobe.aem.transaction.core.ITransactionRecorder;
import com.adobe.aem.transaction.core.model.TransactionRecord;
import com.day.cq.i18n.I18n;
import com.day.cq.wcm.api.WCMMode;
import com.day.cq.wcm.foundation.forms.FormsConstants;
import com.day.cq.wcm.foundation.forms.FormsHelper;

import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.*;
import org.apache.felix.scr.annotations.Properties;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.request.RequestDispatcherOptions;
import org.apache.sling.api.request.RequestParameter;
import org.apache.sling.api.request.RequestParameterMap;
import org.apache.sling.api.resource.*;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.JSONObject;
import org.apache.sling.commons.osgi.ServiceUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.ConcurrentSkipListMap;

/**
 * This file is still present here to support backward compatibility. The public API's which
 * were exposed as part of this servlet have been moved to GuideSubmitUtils. Public API's of this
 * package are not to be used post 6.2
 */

@Component(metatype = false)
@Service(Servlet.class)
@Properties({
        @Property(name = "sling.servlet.resourceTypes", value = "fd/af/components/guideContainer"),
        @Property(name = "sling.servlet.methods", value = "POST"),
        @Property(name = "service.description", value = "Adaptive Form Submit"),
        @Property(name = "sling.servlet.selectors", value = {"af.submit", "af.agreement", "af.signSubmit"})
})

/**
 *  GuideSubmitServlet provides static methods which can be used while writing
 *  custom submit action.
 *  It encapsulates the basic methods required for any custom submit
 *  action to interact with Adaptive Form. Few examples are listed below:
 * 
    *
  • Setting redirect parameters in custom submit action which Adaptive Form must be aware of
  • *
  • Setting the name of the pdf to generate
  • *
  • Setting the forward path(for eg) if one wants to forward the current request to any other rest end point
  • *
* * @since AEM 6.0 */ public class GuideSubmitServlet extends SlingAllMethodsServlet { private static final long serialVersionUID = -5597140632392446185L; public static final String REQ_ATTR_FORWARD_PATH = GuideSubmitUtils.REQ_ATTR_FORWARD_PATH; public static final String REQ_ATTR_FORWARD_OPTIONS = GuideSubmitUtils.REQ_ATTR_FORWARD_OPTIONS; /** * @pad.exclude */ public static final String REQUEST_ATTR_WORKFLOW_PATH = FormsConstants.REQUEST_ATTR_WORKFLOW_PATH; /** * @pad.exclude */ public static final String REQUEST_ATTR_WORKFLOW_PAYLOAD_PATH = FormsConstants.REQUEST_ATTR_WORKFLOW_PAYLOAD_PATH; public static final String REQUEST_ATTR_REDIRECT_PARAMETER_MAP = GuideSubmitUtils.REQUEST_ATTR_REDIRECT_PARAMETER_MAP; private Logger logger = LoggerFactory.getLogger(GuideSubmitServlet.class); @Reference private ITransactionRecorder transactionRecorder; @Reference private GuideModelTransformer guideModelTransformer; @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL_UNARY) private volatile SignAgreementService signAgreementService; @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL_UNARY) private GuidePDFSubmitHelper guidePDFSubmitHelper; @Reference private GuideStoreContentSubmission guideStoreContentSubmission; @Reference(policyOption = ReferencePolicyOption.GREEDY, policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL_UNARY) private FormPortalSubmitPreprocessor formsPortalPreProcessor; @Reference(name = "guideSubmitPostProcessors", referenceInterface = GuideSubmitPostProcessor.class, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC) private Map, GuideSubmitPostProcessor> guideSubmitPostProcessors = new ConcurrentSkipListMap, GuideSubmitPostProcessor>(Collections.reverseOrder()); private TransactionRecord getAdaptiveFormSubmitTransaction(Resource formResource) { String resId = formResource != null ? formResource.getPath() : "", resType = FormsTransactionConstants.ASSET_TYPE_FORM, resSubType = FormsTransactionConstants.ASSET_SUB_TYPE_AF, transactionType = FormsTransactionConstants.TRANSACTION_TYPE_SUBMIT, transactionSubType = null, // not capturing transaction subtype in first cut resName = formResource != null && formResource.getParent() != null ? formResource.getParent().getValueMap().get("jcr:title", "") : ""; Integer transactionCount = 1; // actual billable API return new TransactionRecord(transactionCount, resType, resSubType, transactionType, transactionSubType, resId, resName); } private String getLocale(SlingHttpServletRequest request) { String locale = request.getParameter(GuideConstants.RUNTIME_LOCALE); // thought runtime will never be null // this was done to enable old charles recoding // because passing of runtime locale in submit form was done // for caching all locale json & lib & executing locale specific lib if (locale == null || locale.isEmpty()) { locale = GuideConstants.DEFAULT_FALLBACK_LOCALE; } return locale; } private GuideValidationResult validateForm(SlingHttpServletRequest request, String locale) { ValidationOptions validationOptions = new ValidationOptions.ValidationOptionsBuilder().setFormContainerResource(request.getResource()) .setData(request.getParameter(JcrConstants.JCR_DATA)) .setCaptchaData(request.getParameter(GuideConstants.GUIDE_CAPTCHA_DATA)) .setServerUrl(getServerUrl(request)) .setContextPath(request.getContextPath()) .setLocale(locale) .setFileAttachmentMap(request.getParameter(GuideConstants.GUIDE_FILE_ATTACHMENT_MAP)) .build(); return guideModelTransformer.validateForm(validationOptions); } /** * validates form, creates agreement, deletes draft, create pending sign node * This function does: * Server side validations if applicable * Captcha validation if applicable * Creates Adobe Sign agreement, if applicable * Deletes draft (via FP preprocessor), if applicable * Creates pendingSign node(via FP preprocessor), if applicable * Does Form portal submission if the 'also submit to portal' is checked. * * @param request * @param response * @param submitType - immediate / deferred * @return SignAgreementInfo object, in case agreement was created, else it returns null. */ private SignAgreementInfo doPostPrerequisites(SlingHttpServletRequest request, final SlingHttpServletResponse response, ParameterMap wrappedParameterMap, SubmitType submitType){ SignAgreementInfo signAgreementInfo = null; SlingHttpServletRequest wrappedRequest = request; String locale = getLocale(request); GuideValidationResult guideValidationResult = validateForm(request, locale); try { // If there are errors in the page, set redirect to the guide again with errors if (guideValidationResult != null && guideValidationResult.hasErrors()) { throw new GuideException("Server validation failed."); } guideValidationResult = null; FormSubmitInfo submitInfo = new FormSubmitInfo(); Resource formContainerResource = request.getResource(); boolean isDorConfigured = GuideUtils.isDORConfigured(formContainerResource); final ValueMap properties = ResourceUtil.getValueMap(formContainerResource); Boolean isAdobeSignEnabled = Boolean.valueOf(properties.get(GuideConstants.USE_SIGNED_PDF, "")); Boolean isRedirectURLSet = StringUtils.isNotEmpty(properties.get(GuideConstants.PROP_REDIRECT, "")); String postSignUrl = ""; List fileAttachmentWrapperList = getFileAttachmentWrapperList(wrappedParameterMap); String fileAttachmentMap = request.getParameter(GuideConstants.GUIDE_FILE_ATTACHMENT_MAP); ResourceResolver resourceResolver = request.getResourceResolver(); Authorizable auth = resourceResolver.adaptTo(Authorizable.class); submitInfo.setFormContainerPath(formContainerResource.getPath()); submitInfo.setFormContainerResource(formContainerResource); submitInfo.setContentType(GuideUtils.getDataMimeType(formContainerResource)); submitInfo.setFileAttachments(fileAttachmentWrapperList); submitInfo.setFileAttachmentMap(fileAttachmentMap); submitInfo.setData(request.getParameter(JcrConstants.JCR_DATA)); submitInfo.setFormSubmitter(auth.getID()); submitInfo.setLocale(GuideUtils.getXFALocale(locale)); if ((request.getParameter(GuideConstants.USE_SIGNED_PDF) != null) || isAdobeSignEnabled) { if(isDorConfigured) { try { wrappedParameterMap = guidePDFSubmitHelper.getWrappedParameterMapForPdfSubmit(request, response, wrappedParameterMap); } catch (Exception ex){ // this means dor generation failure, sending internal server error to client throw new GuideException(ex); } String pdfName = (String) request.getAttribute(GuideConstants.PDF_NAME); FileRequestParameter pdfRequestParam = (FileRequestParameter) wrappedParameterMap.get(pdfName)[0]; submitInfo.setDocumentOfRecord(new FileAttachmentWrapper(pdfName, "application/pdf", pdfRequestParam.get())); } else { logger.debug("DOR Template is not configured for the form. Skipping DOR generation"); } } request.setAttribute(GuideConstants.FORM_SUBMIT_INFO, submitInfo); if (isRedirectURLSet && isAdobeSignEnabled) { postSignUrl = getRedirectUrl(wrappedRequest); if (postSignUrl != null) { postSignUrl = getServerUrl(wrappedRequest) + request.getContextPath() + postSignUrl; } } if (isAdobeSignEnabled && submitInfo.getDocumentOfRecord() != null) { signAgreementInfo = signAgreementService.createAgreement(submitInfo, postSignUrl, (SubmitType.IMMEDIATE == submitType)); if (signAgreementInfo.getAgreementId() == null) { GuideError guideError = new GuideError(null, "Error During Agreement Creation"); List guideErrorList = new ArrayList(); guideErrorList.add(guideError); guideValidationResult = new GuideValidationResult(guideErrorList, GuideSubmitErrorCause.AGREEMENT_CREATION); throw new GuideException("There is an error in agreement creation."); } } //Calling forms portal submissions preprocessor to provide information that needs to be passed to actual submit action. //This takes care of creating a record in Forms Portal and deletes if there existed any draft if (formsPortalPreProcessor != null) { Map preProcessorOptions = new HashMap(); preProcessorOptions.put(GuideConstants.FORM_SUBMIT_INFO, submitInfo); preProcessorOptions.put(GuideConstants.ENABLE_PORTAL_SUBMIT, Boolean.valueOf(properties.get(GuideConstants.ENABLE_PORTAL_SUBMIT, "false"))); if (signAgreementInfo != null) { submitInfo.setAgreementId(signAgreementInfo.getAgreementId()); preProcessorOptions.put(GuideConstants.SIGN_AGREEMENT_INFO, signAgreementInfo); } preProcessorOptions.put(GuideConstants.SUBMIT_TYPE, submitType); preProcessorOptions.put(GuideConstants.DRAFT_ID, request.getParameter(GuideConstants.DRAFT_ID)); // TODO remove GuideConstants.AF_SUBMISSION_INFO, compute this from data preProcessorOptions.put(GuideConstants.AF_SUBMISSION_INFO, request.getParameter(GuideConstants.AF_SUBMISSION_INFO)); PortalRecordInfo portalResult = formsPortalPreProcessor.doPreProcess(preProcessorOptions); submitInfo.setPortalRecordInfo(portalResult); } } catch (GuideException e) { sendErrorBackToClient(wrappedRequest, response, wrappedParameterMap, guideValidationResult); logger.error("Could not complete Submit Action due to " + e.getMessage(), e); throw e; } catch (Exception e) { sendErrorBackToClient(wrappedRequest, response, wrappedParameterMap, guideValidationResult); logger.error("Could not complete Submit Action due to " + e.getMessage(), e); throw new GuideException(e); } return signAgreementInfo; } private ParameterMap addGuideValueMap(SlingHttpServletRequest request, final SlingHttpServletResponse response, ParameterMap wrappedParameterMap) { String guideValues = request.getParameter(GuideConstants.GUIDE_VALUES_MAP); try { JSONObject guideValueMapJson = StringUtils.isNotEmpty(guideValues) ? new JSONObject(guideValues) : new JSONObject(); FormSubmitInfo submitInfo = (FormSubmitInfo) request.getAttribute(GuideConstants.FORM_SUBMIT_INFO); PortalRecordInfo portalResult = submitInfo.getPortalRecordInfo(); if (portalResult != null) { String submitId = portalResult.getSubmitID(); if (StringUtils.isNotEmpty(submitId)) { guideValueMapJson.put(GuideConstants.FORMS_PORTAL_SUBMIT_ID, submitId); } String submitLink = portalResult.getSubmitLink(); if (StringUtils.isNotEmpty(submitLink)) { guideValueMapJson.put(GuideConstants.FORMS_PORTAL_SUBMIT_LINK, submitLink); } } RequestParameter paramValue = new FormFieldRequestParameter(guideValueMapJson.toString()); RequestParameter[] paramArr = new RequestParameter[1]; paramArr[0] = paramValue; GuideUtils.addToRequestMap(wrappedParameterMap, GuideConstants.GUIDE_VALUES_MAP, paramArr); } catch (Exception e) { logger.error("Corrupted Guide Value map " + e.getMessage(), e); throw new GuideException(e); } return wrappedParameterMap; } private void doSubmit(SlingHttpServletRequest request, final SlingHttpServletResponse response) { SlingHttpServletRequest wrappedRequest = request; ParameterMap wrappedParameterMap = null; try { wrappedParameterMap = addToNewRequest(wrappedRequest, response); } catch (Exception e) { sendErrorBackToClient(request, response, null, null); logger.error("Failes Submit Action due to " + e.getMessage(), e); throw new GuideException(e); } SignAgreementInfo signAgreementInfo = doPostPrerequisites(request, response, wrappedParameterMap, SubmitType.DEFERRED); Resource formResource = request.getResource(); final ValueMap properties = ResourceUtil.getValueMap(formResource); Boolean isAdobeSignEnabled = Boolean.valueOf(properties.get(GuideConstants.USE_SIGNED_PDF, "")); Boolean isPortalSubmitEnabled = Boolean.valueOf(properties.get(GuideConstants.ENABLE_PORTAL_SUBMIT, "false")); boolean asyncSubmit = "true".equals(request.getParameter(GuideConstants.ASYNC_SUBMIT)) ? true : false; String pendingSignUrl = null; if (signAgreementInfo != null) { pendingSignUrl = signAgreementInfo.getSigningURL(); } if (!asyncSubmit && isAdobeSignEnabled && StringUtils.isNotEmpty(pendingSignUrl)) { try { response.sendRedirect(pendingSignUrl); } catch (Exception e) { // this is redirect failure to signing ui : we may want handle some alert even in non 500 scenario logger.error("Could not redirect to pending sign URL " + e.getMessage(), e); throw new GuideException(e); } return; } // options map is passed as an argument for guide submit post processors. Map optionsMap = new HashMap(); Resource forwardResource = null; String forwardPath = null; try { wrappedParameterMap = addGuideValueMap(wrappedRequest, response, wrappedParameterMap); wrappedRequest = new CustomParameterRequest(request, wrappedParameterMap, "POST"); CustomResponse wrappedResp = new CustomResponse(response); if (!isAdobeSignEnabled) { final String actionType = (properties == null ? "" : properties.get(GuideConstants.ACTION_TYPE, "")); if (StringUtils.isEmpty(actionType)) { logger.warn("Author has not associated any submit action with the form."); } // pass a wrapped response to ignore the exceptions/errors dumped by the scriplet // which is doing the submission // todo: Expose utility API in GuideSubmitUtil to write only few aspects of response, // since we ignore most of the response API apart from getStatus FormsHelper.runAction(actionType, "post", formResource, wrappedRequest, wrappedResp); } if(wrappedResp != null && wrappedResp.getStatus() == HttpServletResponse.SC_INTERNAL_SERVER_ERROR){ // we only check for the status from the wrapped response // only in case of internal server error, we stop the submission post handling and send the error back to client throw new GuideException("Form submission failed due to internal server error from response"); } String redirectUrl = getRedirectUrl(wrappedRequest); FormSubmitInfo submitInfo = (FormSubmitInfo) request.getAttribute(GuideConstants.FORM_SUBMIT_INFO); if (asyncSubmit || redirectUrl == null || redirectUrl.length() == 0) { JSONObject successPayload = prepareSuccessPayload(wrappedRequest, properties, redirectUrl); Map redirectParamsMap = GuideSubmitUtils.getRedirectParameters(wrappedRequest); if (redirectParamsMap == null) { redirectParamsMap = new HashMap<>(); } redirectParamsMap.put(GuideConstants.PROP_KEY_AF_SUCCESS_PAYLOAD, successPayload.toString()); // put agreement id and submit id in case Adobe Sign is enabled. if (isAdobeSignEnabled) { redirectParamsMap.put(GuideConstants.AGREEMENT_ID, signAgreementInfo.getAgreementId()); redirectParamsMap.put(GuideConstants.SYSTEM_ID, submitInfo.getPortalRecordInfo().getSubmitID()); } else if (isPortalSubmitEnabled) { PortalRecordInfo portalRecordInfo = submitInfo.getPortalRecordInfo(); redirectParamsMap.put(GuideConstants.FORMS_PORTAL_SUBMIT_ID, portalRecordInfo.getSubmitID()); redirectParamsMap.put(GuideConstants.SUMMARY_LINK, portalRecordInfo.getSubmitLink()); } /*Setting success payload in request attribute.*/ GuideSubmitUtils.setRedirectParameters(wrappedRequest, redirectParamsMap); redirectUrl = request.getResource().getPath() + "." + GuideConstants.ASYNC_REDIRECT_PAGE; redirectUrl = prepareRedirectUrl(wrappedRequest, redirectUrl); } else if (redirectUrl != null && redirectUrl.length() > 0) { redirectUrl = prepareRedirectUrl(wrappedRequest, redirectUrl); } RequestParameter rpm = new FormFieldRequestParameter(redirectUrl); RequestParameter[] f = new RequestParameter[1]; f[0] = rpm; GuideUtils.addToRequestMap(wrappedParameterMap, GuideConstants.REDIRECT, f); //remove unused parameters like _asyncSubmit, xfaDom, _useSignedPdf. can add new parameters later. removeUnusedParameters(wrappedParameterMap); wrappedRequest = new CustomParameterRequest(request, wrappedParameterMap, "POST"); forwardPath = getForwardPath(wrappedRequest); if (forwardPath != null && forwardPath.length() > 0) { forwardResource = wrappedRequest.getResourceResolver().resolve(forwardPath); request.getRequestDispatcher(forwardResource, getForwardOptions(wrappedRequest)).forward(wrappedRequest, response); } else { redirectUrl = GuideSubmitUtils.addContextPath(redirectUrl, request.getContextPath()); response.sendRedirect(redirectUrl); } if (!isAdobeSignEnabled) { // Calling all the Guide submit post processors available // this is for backward compatibility support for (GuideSubmitPostProcessor guideSubmitPostProcessor : this.guideSubmitPostProcessors.values()) { try { guideSubmitPostProcessor.handlePostProcess(submitInfo.getData(), submitInfo.getFileAttachments(), optionsMap); } catch (Exception e) { // GuideSubmitPostProcessor is neither publically exposed nor do we implement it. // so far we are not propagating error back to client. logger.error("The current guideSubmitPostProcessor could not give path", e); } } } } catch (GuideException e) { sendErrorBackToClient(request, response, wrappedParameterMap, null); logger.error("Could not complete Submit Action due to " + e.getMessage(), e); throw e; } catch (Exception e) { sendErrorBackToClient(request, response, wrappedParameterMap, null); logger.error("Could not complete Submit Action due to " + e.getMessage(), e); throw new GuideException(e); } finally { try { // if the action is store or storepdf then clean the permission that was granted to store the content. // Note that this has been incorporated to call unsetPriviledge and STORE_CONTENT_TEMP_PERMISSION_PROPERTY // only for the store and storepdf actions as only we are writing this property while creating // the sling folder for submission // doing the same in finally block so that if anything fails we at least unset the permissions if we gave them if (forwardResource != null) { ModifiableValueMap forwardResourceProperties = forwardResource.adaptTo(ModifiableValueMap.class); if (forwardResourceProperties != null && forwardResourceProperties.containsKey(GuideConstants.STORE_CONTENT_TEMP_PERMISSION_PROPERTY)) { forwardResourceProperties.remove(GuideConstants.STORE_CONTENT_TEMP_PERMISSION_PROPERTY); request.getResourceResolver().commit(); guideStoreContentSubmission.unsetPrivilegesForStoreContent(GuideUtils.getUserSessionFromRequest(request), forwardPath); } } } catch (Exception ex) { logger.error("Could not unset privileges", ex); } } } private void sendAgreementInfo(SlingHttpServletRequest request, final SlingHttpServletResponse response) { SlingHttpServletRequest wrappedRequest = request; ParameterMap wrappedParameterMap = addToNewRequest(wrappedRequest, response); SignAgreementInfo signAgreementInfo = doPostPrerequisites(request, response, wrappedParameterMap, SubmitType.IMMEDIATE); JSONObject jsonObject = new JSONObject(); FormSubmitInfo submitInfo = (FormSubmitInfo) request.getAttribute(GuideConstants.FORM_SUBMIT_INFO); PortalRecordInfo portalResult = submitInfo.getPortalRecordInfo(); try { if (StringUtils.isNotEmpty(signAgreementInfo.getSigningURL())) { jsonObject.put(GuideConstants.SIGNING_URL, signAgreementInfo.getSigningURL()); } jsonObject.put(GuideConstants.AGREEMENT_ID, signAgreementInfo.getAgreementId()); jsonObject.put(GuideConstants.SYSTEM_ID, portalResult.getSubmitID()); sendJSONResponse(request, response, jsonObject); } catch (GuideException e) { logger.error("Failed to create response JSON " + e.getMessage(), e); throw e; } catch (Exception e) { logger.error("Failed to create response JSON " + e.getMessage(), e); throw new GuideException(e); } } private void doSignSubmit(SlingHttpServletRequest request, final SlingHttpServletResponse response) { Resource formContainerResource = request.getResource(); Resource signerInfoResource = formContainerResource.getChild(GuideConstants.SIGNER_INFO_RESOURCE); String signConfigPath = ""; Map result; String agreementId = request.getParameter(GuideConstants.AGREEMENT_ID); String systemId = request.getParameter(GuideConstants.SYSTEM_ID); String newSystemId = ""; String pendingSignId = ""; String link = ""; if (signerInfoResource != null) { signConfigPath = signerInfoResource.getValueMap().get(GuideConstants.SIGN_CONFIG_PATH, ""); } if (StringUtils.isNotEmpty(signConfigPath)) { result = signAgreementService.submitAgreement(systemId, agreementId, signConfigPath); if (result != null) { link = (String) result.get(GuideConstants.SUMMARY_LINK); newSystemId = (String) result.get(GuideConstants.FORMS_PORTAL_SUBMIT_ID); pendingSignId = (String) result.get(GuideConstants.FORMS_PORTAL_PENDING_SIGN_ID); } else { pendingSignId = systemId; link = "/content/forms/portal/render.dor.pdf/pendingSign/" + pendingSignId; } } Resource afResource = GuideSubmitUtils.getParentResource(formContainerResource, JcrResourceConstants.CQ_PAGE); String formName = afResource.getValueMap().get(GuideConstants.JCR_TITLE, afResource.getName()); String submitId = ""; if (StringUtils.isNotEmpty(newSystemId)) { submitId = newSystemId; } else if (StringUtils.isNotEmpty(pendingSignId)) { submitId = pendingSignId; } try { JSONObject jsonObject = new JSONObject(); jsonObject.put(GuideConstants.AGREEMENT_ID, agreementId); jsonObject.put(GuideConstants.SUMMARY_FORM_NAME, formName); jsonObject.put(GuideConstants.FORMS_PORTAL_SUBMIT_ID, submitId); jsonObject.put(GuideConstants.SUMMARY_OWNER, GuideSubmitUtils.getUserID(request)); jsonObject.put(GuideConstants.SUMMARY_LINK, link); sendJSONResponse(request, response, jsonObject); } catch (Exception e) { logger.error("Failed to create response JSON " + e.getMessage(), e); throw new GuideException(e); } } private void sendJSONResponse(SlingHttpServletRequest request, final SlingHttpServletResponse response, JSONObject jsonObject) { SlingHttpServletRequest wrappedRequest = request; try { response.setContentType(GuideConstants.CONTENT_TYPE_APPLICATION_JSON); response.getWriter().write(jsonObject.toString()); } catch (Exception e) { logger.error("Could not send response back due to " + e.getMessage(), e); throw new GuideException(e); } } /** * @pad.exclude */ protected void doPost(SlingHttpServletRequest request, final SlingHttpServletResponse response) throws ServletException, IOException { String[] requestSelectors = request.getRequestPathInfo().getSelectors(); String requestSelector = ""; if (requestSelectors.length > 1) { requestSelector = requestSelectors[1]; } boolean recordTransaction = true; try { transactionRecorder.startContext(); if (GuideConstants.SIGN_SUBMIT.equals(requestSelector)) { recordTransaction = false; doSignSubmit(request, response); } else if (GuideConstants.AGREEMENT.equals(requestSelector)) { sendAgreementInfo(request, response); } else { // "submit" - GuideConstants.SUBMIT doSubmit(request, response); } if (recordTransaction) { if (response.getStatus() < HttpServletResponse.SC_BAD_REQUEST) { TransactionRecord transactionRecord = getAdaptiveFormSubmitTransaction(request.getResource()); transactionRecorder.recordTransaction(transactionRecord); } else { transactionRecorder.discardTransaction(); } } } catch (TransactionException e) { logger.error("Transaction exception while recording transaction", e); } catch (Exception e) { if (recordTransaction) { transactionRecorder.discardTransaction(); } logger.error("Exception in post request. " + e.getMessage(), e); } finally { transactionRecorder.endContext(); } } private void sendErrorBackToClient(SlingHttpServletRequest request, SlingHttpServletResponse response, ParameterMap wrappedParameterMap, GuideValidationResult guideValidationResult) { if(guideValidationResult == null){ // setting som expression as null, since error is for entire form GuideError guideError = new GuideError(null, "Error During Form Submission"); List guideErrorList = new ArrayList(); guideErrorList.add(guideError); guideValidationResult = new GuideValidationResult(guideErrorList, GuideSubmitErrorCause.FORM_SUBMISSION); } // send the error list to the client back using forward path SlingHttpServletRequest wrappedErrorRequest = new CustomParameterRequest(request, wrappedParameterMap, "GET"); wrappedErrorRequest.setAttribute(GuideConstants.GUIDE_ERROR_LIST, guideValidationResult); //Getting json error object from guideValidationResult JSONObject errorObject = guideValidationResult.getValidationPayload(); //For sync submit setting errorObject as an attribute wrappedErrorRequest.setAttribute(GuideConstants.GUIDE_ERROR, errorObject); // Making sure that the request is always in disabled mode // Not required if considering this code would always run in publish instance wrappedErrorRequest.setAttribute(WCMMode.REQUEST_ATTRIBUTE_NAME, WCMMode.DISABLED); // Set the data attribute to restore the state wrappedErrorRequest.setAttribute("data", request.getParameter("jcr:data")); // Create the dispatcher options with no suffix and selector RequestDispatcherOptions options = new RequestDispatcherOptions(); options.setReplaceSuffix(null); options.setReplaceSelectors(null); // In case of ajax submit, when server validation fails, we send an error response with code 500. // There is no support to send the error list or to focus the component whose validation fails yet. if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With")) || "true".equals(request.getParameter(GuideConstants.ASYNC_SUBMIT))) { response.setStatus(500); response.setContentType(GuideConstants.CONTENT_TYPE_APPLICATION_JSON); try { response.getWriter().write(errorObject.toString()); } catch (IOException e) { if (errorObject != null) { logger.debug("sendErrorBackToClient: errorObject:" + errorObject.toString()); } logger.error("sendErrorBackToClient: failed to write to response " + e.getMessage(), e); } } else { try { // Forward the request to the page request.getRequestDispatcher(request.getParameter(GuideConstants.SELF_URL) + ".html", options).forward(wrappedErrorRequest, response); } catch (Exception e) { logger.error("sendErrorBackToClient: failed to forward request " + e.getMessage(), e); } } } /** * @pad.exclude */ protected void bindGuideSubmitPostProcessors(final GuideSubmitPostProcessor guideSubmitPostProcessor, Map config) { this.guideSubmitPostProcessors.put(ServiceUtil.getComparableForServiceRanking(config), guideSubmitPostProcessor); } /** * @pad.exclude */ protected void unbindGuideSubmitPostProcessors(final GuideSubmitPostProcessor guideSubmitPostProcessor, Map config) { this.guideSubmitPostProcessors.remove(ServiceUtil.getComparableForServiceRanking(config)); } private RequestDispatcherOptions getForwardOptions(final ServletRequest req) { return (RequestDispatcherOptions) req.getAttribute(REQ_ATTR_FORWARD_OPTIONS); } private String getServerUrl(final SlingHttpServletRequest req) { String scheme = req.getScheme(); // http String serverName = req.getServerName(); // hostname.com int serverPort = req.getServerPort(); // 80 // Note: Context Path has to be explicitly appended to the URL always // If at all client requires context path, use guideBridge._getUrl method for this // String contextPath = req.getContextPath(); // /mywebapp // Reconstruct original requesting URL StringBuffer url = new StringBuffer(); url.append(scheme).append("://").append(serverName); if ((serverPort != 80) && (serverPort != 443)) { url.append(":").append(serverPort); } //if(contextPath != null){ // url.append(contextPath); //} return url.toString(); } /** * The API returns the path to forward the current request * * @param req sling request */ private String getForwardPath(final SlingHttpServletRequest req) { return (String) req.getAttribute(REQ_ATTR_FORWARD_PATH); } /** * This API should be used to set the path to forward the current request * * @param req Sling request * @param path Path to forward the current request * @param selector Sling selector to use while forwarding the request to the path. Null if no selector to be used * @param suffix Suffix to use while forwarding the request to the path. Null if no selector to be used * @deprecated As of release 6.2, replaced by {@link com.adobe.aemds.guide.utils.GuideSubmitUtils.setForwardPath} */ @Deprecated public static void setForwardPath(final SlingHttpServletRequest req, final String path, String selector, String suffix) { GuideSubmitUtils.setForwardPath(req, path, selector, suffix); } /** * This API returns the redirect URL set in the request * * @param request sling request */ private static String getRedirectUrl(SlingHttpServletRequest request) { String redirectUrl = null; redirectUrl = (String) request.getAttribute(GuideConstants.REDIRECT); if (redirectUrl == null) { redirectUrl = request.getParameter(GuideConstants.REDIRECT); } return redirectUrl; } /** * This API should be used to set the redirect url * * @param req sling request * @param redirectUrl redirect url to set in the current request object * @deprecated As of release 6.2, replaced by {@link com.adobe.aemds.guide.utils.GuideSubmitUtils.setRedirectUrl} */ @Deprecated public static void setRedirectUrl(final SlingHttpServletRequest req, final String redirectUrl) { GuideSubmitUtils.setRedirectUrl(req, redirectUrl); } /** * This API returns redirect parameters set in the current request. To set the * redirect parameters, check {@link #setRedirectParameters} * * @param request sling request * @return Map containing parameter names with their corresponding values * @deprecated As of release 6.2, replaced by {@link com.adobe.aemds.guide.utils.GuideSubmitUtils.getRedirectParameters} */ @Deprecated public static Map getRedirectParameters(SlingHttpServletRequest request) { return GuideSubmitUtils.getRedirectParameters(request); } /** * Sets redirect parameters to the current request * * @param request sling request * @param value Map represent the redirect paramters to be set * @deprecated As of release 6.2, replaced by {@link com.adobe.aemds.guide.utils.GuideSubmitUtils.setRedirectParameters} */ @Deprecated public static void setRedirectParameters(SlingHttpServletRequest request, Map value) { GuideSubmitUtils.setRedirectParameters(request, value); } /** * Returns the name of the pdf which is set from the current client request using {@link #setRequestAttrPdfName(org.apache.sling.api.SlingHttpServletRequest, String)} * * @param request Interface to provide client request information to a servlet. * @return the string represent the pdf name * @pad.exclude Exclude from Published API. */ @Deprecated public static String getReqAttrPdfName(SlingHttpServletRequest request) { return GuideSubmitUtils.getReqAttrPdfName(request); } /** * This should be used to set the pdf name in the current client request * * @param request Interface to provide client request information to a servlet. * @param value String representing the name of the pdf * @pad.exclude Exclude from Published API. */ public static void setRequestAttrPdfName(SlingHttpServletRequest request, String value) { request.setAttribute(GuideConstants.PDF_NAME, value); } private ParameterMap addToNewRequest(SlingHttpServletRequest request, SlingHttpServletResponse response) { ParameterMap wrappedParameterMap = new ParameterMap(); RequestParameterMap originalParams = request.getRequestParameterMap(); List attachments = new ArrayList(); FileAttachmentWrapper fileAttachmentWrapper; for (Map.Entry param : originalParams.entrySet()) { RequestParameter rp = param.getValue()[0]; boolean isFile = false; isFile = param.getKey().indexOf("_guideFileAttachment.") != -1 && "_guideFileAttachment.".equals(param.getKey().substring(0, 21)); if (!rp.isFormField()) { // This is the special case of attachments //for anonymous users where // we would get file dom directly RequestParameter[] fileRpm = new RequestParameter[1]; fileRpm[0] = new FileRequestParameter(rp.getName(), rp.get(), rp.getContentType()); GuideUtils.addToRequestMap(wrappedParameterMap, param.getKey(), fileRpm); } else if (!isFile) { GuideUtils.addToRequestMap(wrappedParameterMap, param.getKey(), param.getValue()); } else { /* 21 is the length of _guideFileAttachment. which is prefixed to the parameter name * and the value of the parameter is the URL. * TODO: need to fix this hardcoding and add some constants. */ String paramName = param.getKey().substring(21); //so that complete name goes into the filename including fileupload id String filename = paramName; RequestParameter rpm = param.getValue()[0]; RequestParameter[] fileRpm = new RequestParameter[1]; String fileUrl = rpm.toString(); String normalizedFileUrl = ""; /* * We are normalizing the fileUrl provided by draftProviderService as well. It will be a path as well * in the current CQ Instance only and not a full HTTP/HTTPS/FTP/etc URL */ normalizedFileUrl = ResourceUtil.normalize(fileUrl); /* * normalizedFileUrl can be null in the cases if path reaches beyond root, e.g. * /tmp/fd/af/../../../../some/path */ if (normalizedFileUrl == null) { logger.error("[AEMAF] Invalid Path in File Attachement " + fileUrl); throw new GuideException("Invalid Path in File Attachement " + fileUrl); } if (normalizedFileUrl.startsWith(GuideConstants.GUIDE_TEMP_PATH)) { Resource fileResource = request.getResourceResolver().getResource(normalizedFileUrl); if (fileResource != null) { fileRpm[0] = new FileRequestParameter(filename, fileResource); } } else { try { ParameterMap newMap = new ParameterMap(); SlingHttpServletRequest newRequest = new CustomParameterRequest(request, newMap, "GET"); SlingHttpServletResponse newResponse = new CustomResponse(response); newRequest.getRequestDispatcher(normalizedFileUrl, new RequestDispatcherOptions()).forward(newRequest, newResponse); byte[] fileBytes = ((CustomResponse) newResponse).getCopy(); String contentType = newResponse.getContentType(); fileRpm[0] = new FileRequestParameter(filename, fileBytes, contentType); } catch (Exception e) { logger.error("[AEMAF]Error while hitting REST URL", e); throw new GuideException(e); } } GuideUtils.addToRequestMap(wrappedParameterMap, paramName, fileRpm); } } return wrappedParameterMap; } private List getFileAttachmentWrapperList(ParameterMap parameterMap) { List fileAttachments = new ArrayList(); for (Map.Entry param : parameterMap.entrySet()) { RequestParameter[] rpm = param.getValue(); if (rpm != null && rpm.length > 0 && rpm[0] == null) { logger.error("getFileAttachmentWrapperList: rpm[0] is null for:" + param.getKey()); throw new GuideException("Exception: data loss - missing parameter value"); } if (rpm != null && rpm.length > 0 && !rpm[0].isFormField()) { FileAttachmentWrapper fileAttachment = new FileAttachmentWrapper(rpm[0].getFileName(), rpm[0].getContentType(), rpm[0].get()); fileAttachments.add(fileAttachment); } } return fileAttachments; } private String prepareRedirectUrl(SlingHttpServletRequest request, String redirectUrl) throws UnsupportedEncodingException { if (redirectUrl.indexOf("?") == -1) { redirectUrl = redirectUrl + "?"; } else { redirectUrl = redirectUrl + "&"; } Map redirectParameters = GuideSubmitUtils.getRedirectParameters(request); if (redirectParameters != null && !redirectParameters.isEmpty()) { for (Map.Entry param : redirectParameters.entrySet()) { redirectUrl = redirectUrl + URLEncoder.encode(param.getKey(), GuideConstants.UTF_8) + "=" + URLEncoder.encode(param.getValue(), GuideConstants.UTF_8) + "&"; } } if (redirectUrl.charAt(redirectUrl.length() - 1) == '&' || redirectUrl.charAt(redirectUrl.length() - 1) == '?') { redirectUrl = redirectUrl.substring(0, redirectUrl.length() - 1); } return redirectUrl; } private void removeUnusedParameters(ParameterMap map) { map.remove(GuideConstants.USE_SIGNED_PDF); map.remove(GuideConstants.ASYNC_SUBMIT); } private JSONObject prepareSuccessPayload(SlingHttpServletRequest request, ValueMap properties, String redirectUrl) throws UnsupportedEncodingException { String aemFormCompPath = request.getParameter(GuideConstants.REQUEST_PROPERTY_AEM_FORM_COMPONENT_PATH), defaultThankYouPageUrl = request.getParameter(GuideConstants.REQUEST_PROPERTY_GUIDE_START) + "." + GuideConstants.THANKYOU_PAGE, defaultThankYouMessage = I18n.get(request, "Thank you for submitting the form."), thankYouOption = null, thankYouContent = null, locale = getLocale(request); I18n i18n = new I18n(request.getResourceBundle(new Locale(locale))); Resource aemFormResource = StringUtils.isBlank(aemFormCompPath) ? null : request.getResourceResolver().getResource(aemFormCompPath); if (redirectUrl == null) { redirectUrl = defaultThankYouPageUrl; } if (aemFormResource != null) { /* aemFormResource is present. * Use case e.g: Request coming from AEM Form. * Now creating a thankYou Configuration w.r.t AEM Form. * */ final ValueMap aemFormProperties = aemFormResource.adaptTo(ValueMap.class); thankYouOption = aemFormProperties.get(AEMForm.PROP_THANK_YOU_CONFIG, GuideConstants.ThankYouOption.PAGE.toString()); String thankYouPage = GuideUtils.getRedirectUrl(aemFormProperties.get(AEMForm.PROP_THANK_YOU_PAGE, ""), null); String thankYouMessage = aemFormProperties.get(AEMForm.PROP_THANK_YOU_MESSAGE, defaultThankYouMessage); if (GuideConstants.ThankYouOption.PAGE.toString().equals(thankYouOption)) { if (StringUtils.isBlank(thankYouPage)) { thankYouContent = GuideSubmitUtils.addContextPath(defaultThankYouPageUrl, request.getContextPath()); } else { thankYouContent = GuideSubmitUtils.addContextPath(thankYouPage, request.getContextPath()); } //This will append the parameters to the redirect url. Use Case: RestEnd point submit action. thankYouContent = prepareRedirectUrl(request, thankYouContent); } else { thankYouContent = thankYouMessage; } } else { /* aemFormResource is null. * Use case e.g: normal async submission case. * Now creating a thankYou Configuration w.r.t GuideContainer. **/ thankYouOption = properties.get(GuideConstants.PROP_THANK_YOU_OPTION, GuideConstants.ThankYouOption.PAGE.toString()); if (GuideConstants.ThankYouOption.PAGE.toString().equals(thankYouOption)) { thankYouContent = GuideSubmitUtils.addContextPath(redirectUrl, request.getContextPath()); //This will append the parameters to the redirect url. Use Case: RestEnd point submit action. thankYouContent = prepareRedirectUrl(request, thankYouContent); } else { thankYouContent = properties.get(GuideConstants.PROP_THANK_YOU_OPTION_MESSAGE, defaultThankYouMessage); thankYouContent = GuideUtils.translateOrReturnOriginal(thankYouContent, i18n); } } //Preparing success payload using thankYouOption and thankYouContent. JSONObject successPayload = new JSONObject(); try { successPayload.put(GuideConstants.PROP_THANK_YOU_OPTION, thankYouOption); successPayload.put(GuideConstants.PROP_THANK_YOU_OPTION_CONTENT, thankYouContent); } catch (JSONException e) { logger.error("Error while writing JSON.", e); } return successPayload; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy