/*
* #%L
* ACS AEM Commons Bundle
* %%
* Copyright (C) 2013 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.forms.helpers.impl;
import com.adobe.acs.commons.forms.Form;
import com.adobe.acs.commons.forms.helpers.FormHelper;
import com.adobe.acs.commons.forms.helpers.PostRedirectGetFormHelper;
import com.adobe.acs.commons.forms.impl.FormImpl;
import com.adobe.acs.commons.util.TypeUtil;
import com.day.cq.wcm.api.Page;
import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
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.commons.json.JSONException;
import org.apache.sling.commons.json.JSONObject;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
/**
* ACS AEM Commons - Forms - POST-Redirect-GET Form Helper
*
*/
@Component(inherit = true)
@Property(label = "Service Ranking",
name = Constants.SERVICE_RANKING,
intValue = FormHelper.SERVICE_RANKING_POST_REDIRECT_GET)
@Service(value = { FormHelper.class, PostRedirectGetFormHelper.class })
public class PostRedirectGetFormHelperImpl extends AbstractFormHelperImpl implements PostRedirectGetFormHelper {
private static final Logger log = LoggerFactory.getLogger(PostRedirectGetFormHelperImpl.class);
@Override
public final Form getForm(final String formName, final SlingHttpServletRequest request) {
return getForm(formName, request, null);
}
@Override
public final Form getForm(final String formName, final SlingHttpServletRequest request, final SlingHttpServletResponse response) {
if (this.doHandlePost(formName, request)) {
log.debug("Getting FORM [ {} ] from POST parameters", formName);
return this.getPostForm(formName, request);
} else if (this.doHandleGet(formName, request)) {
log.debug("Getting FORM [ {} ] from GET parameters", formName);
return this.getGetForm(formName, request, response);
}
log.debug("Creating empty form for FORM [ {} ]", formName);
return new FormImpl(formName, request.getResource().getPath());
}
@Override
public final void sendRedirect(Form form, String path, SlingHttpServletResponse response) throws IOException,
JSONException {
this.sendRedirect(form, path, null, response);
}
@Override
public final void sendRedirect(Form form, Page page, SlingHttpServletResponse response) throws IOException,
JSONException {
this.sendRedirect(form, page, null, response);
}
@Override
public final void sendRedirect(Form form, Resource resource, SlingHttpServletResponse response) throws
IOException, JSONException {
this.sendRedirect(form, resource, null, response);
}
@Override
public void sendRedirect(Form form, String path, String formSelector, SlingHttpServletResponse response)
throws IOException, JSONException {
final String url = this.getRedirectPath(form, path, formSelector);
response.sendRedirect(url);
}
@Override
public void sendRedirect(Form form, Page page, String formSelector, SlingHttpServletResponse response)
throws IOException, JSONException {
final String url = this.getRedirectPath(form, page, formSelector);
response.sendRedirect(url);
}
@Override
public void sendRedirect(Form form, Resource resource, String formSelector,
SlingHttpServletResponse response) throws IOException, JSONException {
final String url = this.getRedirectPath(form, resource, formSelector);
response.sendRedirect(url);
}
@Override
public final void renderForm(final Form form, final Page page, final SlingHttpServletRequest request,
final SlingHttpServletResponse response)
throws IOException, ServletException, JSONException {
this.sendRedirect(form, page, this.getFormSelector(request), response);
}
@Override
public final void renderForm(final Form form, final Resource resource, final SlingHttpServletRequest request,
final SlingHttpServletResponse response)
throws IOException, ServletException, JSONException {
this.sendRedirect(form, resource, this.getFormSelector(request), response);
}
@Override
public final void renderForm(final Form form, final String path, final SlingHttpServletRequest request,
final SlingHttpServletResponse response)
throws IOException, ServletException, JSONException {
this.sendRedirect(form, path, this.getFormSelector(request), response);
}
@Override
public final void renderOtherForm(Form form, String path, String formSelector, SlingHttpServletRequest request,
SlingHttpServletResponse response)
throws IOException, ServletException, JSONException {
this.sendRedirect(form, path, formSelector, response);
}
@Override
public final void renderOtherForm(Form form, Page page, String formSelector, SlingHttpServletRequest request,
SlingHttpServletResponse response)
throws IOException, ServletException, JSONException {
this.sendRedirect(form, page, formSelector, response);
}
@Override
public final void renderOtherForm(Form form, Resource resource, String formSelector,
SlingHttpServletRequest request, SlingHttpServletResponse response)
throws IOException, ServletException, JSONException {
this.sendRedirect(form, resource, formSelector, response);
}
/**
* Determines if this Form Manager should handle this request.
*
* @param formName
* @param request
* @return
*/
protected final boolean doHandle(final String formName, final SlingHttpServletRequest request) {
return this.doHandleGet(formName, request) || this.doHandlePost(formName, request);
}
/**
* Checks if this Form Manager should handle this request as a GET request.
*
* @param formName
* @param request
* @return
*/
protected boolean doHandleGet(final String formName, final SlingHttpServletRequest request) {
//noinspection SimplifiableIfStatement
if (StringUtils.equalsIgnoreCase("GET", request.getMethod())) {
return (StringUtils.isNotBlank(request.getParameter(this.getGetLookupKey(formName))));
} else {
return false;
}
}
/**
* Derives the form from the request's Query Parameters as best it can
* <p>
* Falls back to an empty form if it runs into problems.
* Fallback is due to ease of (inadvertent) tampering with query params
*
* @param formName
* @param request
* @return
*/
protected Form getGetForm(final String formName, final SlingHttpServletRequest request, final SlingHttpServletResponse response) {
Map<String, String> data = new HashMap<String, String>();
Map<String, String> errors = new HashMap<String, String>();
final String requestData = getRawFormData(formName, request, response);
if (StringUtils.isBlank(requestData)) {
return new FormImpl(formName, request.getResource().getPath());
}
try {
final JSONObject jsonData = new JSONObject(requestData);
final String incomingFormName = jsonData.optString(KEY_FORM_NAME);
// Double-check the form names; only inject matching forms
if (StringUtils.equals(incomingFormName, formName)) {
final JSONObject incomingJsonForm = jsonData.optJSONObject(KEY_FORM);
if (incomingJsonForm != null) {
data = TypeUtil.toMap(incomingJsonForm, String.class);
log.debug("Form data: {}", data);
}
final JSONObject incomingJsonErrors = jsonData.optJSONObject(KEY_ERRORS);
if (incomingJsonErrors != null) {
errors = TypeUtil.toMap(incomingJsonErrors, String.class);
log.debug("Form data: {}", errors);
}
}
} catch (JSONException e) {
log.warn("Cannot parse query parameters for request: {}", requestData);
return new FormImpl(formName, request.getResource().getPath());
}
return new FormImpl(formName,
request.getResource().getPath(),
this.getProtectedData(data),
this.getProtectedErrors(errors));
}
protected String getRawFormData(final String formName, final SlingHttpServletRequest request,
final SlingHttpServletResponse response) {
// Get the QP lookup for this form
return this.decode(request.getParameter(this.getGetLookupKey(formName)));
}
/**
* Returns the Query Parameter name for this form.
*
* @param formName
* @return
*/
protected final String getGetLookupKey(final String formName) {
return KEY_PREFIX_FORM_NAME + formName;
}
/**
* Created the URL to the failure page with re-population info and error info.
*
* @param form
* @param page
* @return
* @throws org.apache.sling.commons.json.JSONException
*
* @throws java.io.UnsupportedEncodingException
*
*/
protected final String getRedirectPath(final Form form, final Page page, final String formSelector) throws
JSONException,
UnsupportedEncodingException {
return getRedirectPath(form, page.adaptTo(Resource.class), formSelector);
}
/**
* Created the URL to the failure page with re-population info and error info.
*
* @param form
* @param resource
* @return
* @throws org.apache.sling.commons.json.JSONException
*
* @throws java.io.UnsupportedEncodingException
*
*/
protected final String getRedirectPath(final Form form, final Resource resource, final String formSelector) throws
JSONException,
UnsupportedEncodingException {
return getRedirectPath(form, resource.getPath() + FormHelper.EXTENSION, formSelector);
}
/**
* Created the URL to the failure page with re-population info and error info.
*
* @param form
* @param path
* @return
* @throws org.apache.sling.commons.json.JSONException
*
*/
protected String getRedirectPath(final Form form, final String path, final String formSelector) throws
JSONException {
String redirectPath = path;
redirectPath += this.getSuffix();
if (StringUtils.isNotBlank(formSelector)) {
redirectPath += "/" + formSelector;
}
redirectPath += "?";
redirectPath += this.getQueryParameters(form);
return redirectPath;
}
/**
* *
* Returns the a string of query parameters that hold Form and Form Error.
* data
*
* @return
* @throws org.apache.sling.commons.json.JSONException
*
*/
protected final String getQueryParameters(Form form) throws JSONException {
String params = "";
form = this.clean(form);
if (form.hasData() || form.hasErrors()) {
params = this.getGetLookupKey(form.getName());
params += "=";
params += getQueryParameterValue(form);
}
return params;
}
protected final String getQueryParameterValue(Form form) throws JSONException {
boolean hasData = false;
final JSONObject jsonData = new JSONObject();
form = this.clean(form);
jsonData.put(KEY_FORM_NAME, form.getName());
if (form.hasData()) {
final JSONObject jsonForm = new JSONObject(form.getData());
jsonData.put(KEY_FORM, jsonForm);
hasData = true;
}
if (form.hasErrors()) {
final JSONObject jsonError = new JSONObject(form.getErrors());
jsonData.put(KEY_ERRORS, jsonError);
hasData = true;
}
return hasData ? this.encode(jsonData.toString()) : "";
}
}