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

com.day.cq.wcm.foundation.forms.FormsHelper Maven / Gradle / Ivy

There is a newer version: 6.5.21
Show newest version
/*
 * Copyright 1997-2010 Day Management AG
 * Barfuesserplatz 6, 4001 Basel, Switzerland
 * All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * Day Management AG, ("Confidential Information"). You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Day.
 */
package com.day.cq.wcm.foundation.forms;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringEscapeUtils;
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.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.scripting.SlingBindings;
import org.apache.sling.api.scripting.SlingScriptHelper;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.jcr.JsonItemWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.granite.xss.XSSAPI;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.wcm.api.LanguageManager;
import com.day.cq.wcm.api.WCMMode;
import com.day.cq.wcm.api.components.ComponentContext;
import com.day.cq.wcm.foundation.ELEvaluator;
import com.day.cq.wcm.foundation.forms.impl.FormChooserServlet;
import com.day.cq.wcm.foundation.forms.impl.FormStructureHelperImpl;
import com.day.cq.wcm.foundation.forms.impl.FormsUtil;
import com.day.cq.wcm.foundation.forms.impl.JspSlingHttpServletResponseWrapper;
import com.day.cq.wcm.foundation.forms.impl.ResourceWrapper;

/**
 * Helper class for the forms components.
 */
public class FormsHelper {

    /** The logger. */
    private static final Logger LOGGER = LoggerFactory.getLogger(FormsHelper.class.getName());

    private FormsHelper() {
        // no instances
    }

    public static final String REQ_ATTR_GLOBAL_LOAD_MAP      = "cq.form.loadmap";
    public static final String REQ_ATTR_GLOBAL_LOAD_RESOURCE = "cq.form.loadresource";
    public static final String REQ_ATTR_EDIT_RESOURCES       = FormResourceEdit.RESOURCES_ATTRIBUTE;
    public static final String REQ_ATTR_CLIENT_VALIDATION    = "cq.form.clientvalidation";
    public static final String REQ_ATTR_FORMID               = "cq.form.id";
    public static final String REQ_ATTR_WRITTEN_JAVASCRIPT   = "cq.form.javascript";
    public static final String REQ_ATTR_ACTION_SUFFIX        = "cq.form.action.suffix";
    public static final String REQ_ATTR_FORWARD_PATH         = "cq.form.forward.path";
    public static final String REQ_ATTR_FORWARD_OPTIONS      = "cq.form.forward.options";
    public static final String REQ_ATTR_IS_INIT              = "cq.form.init";
    public static final String REQ_ATTR_READ_ONLY            = "cq.form.readonly";
    public static final String REQ_ATTR_REDIRECT             = "cq.form.redirect";
    public static final String REQ_ATTR_REDIRECT_TO_REFERRER = FormsConstants.REQUEST_ATTR_REDIRECT_TO_REFERRER;
    public static final String REQ_ATTR_PROP_WHITELIST         = "cq.form.prop.whitelist";
    public static final String REQ_ATTR_EXPRESSIONS_ENABLED    = "cq.form.expressions.enabled";
    public static final String REQ_ATTR_FORM_STRUCTURE_HELPER = "cq.form.formstructurehelper";

    private static final FormStructureHelper defaultFormStructureHelper = new FormStructureHelperImpl();


    /**
     * Signal the start of the form.
     * Prepare the request object, write out the client javascript (if the form
     * is configured accordingly) and write out the start form tag and hidden fields:
     * {@link FormsConstants#REQUEST_PROPERTY_FORMID} with the value of the form id.
     * {@link FormsConstants#REQUEST_PROPERTY_FORM_START} with the relative path to the form start par
     * and _charset_ with the value UTF-8
     *
     * @param request The current request.
     * @param response The current response.
     * @param out The jsp writer.
     * @deprecated Use {@link #startForm(SlingHttpServletRequest, SlingHttpServletResponse)}
     * @throws IOException if form generation caused an error
     * @throws ServletException if form generation caused an error
     */
    @Deprecated
    public static void startForm(final SlingHttpServletRequest request,
                                 final SlingHttpServletResponse response,
                                 final JspWriter out)
    throws IOException, ServletException {
        startForm(request, new JspSlingHttpServletResponseWrapper(response, out));
    }

    /**
     * Signal the start of the form.
     * Prepare the request object, write out the client javascript (if the form
     * is configured accordingly) and write out the start form tag and hidden fields:
     * {@link FormsConstants#REQUEST_PROPERTY_FORMID} with the value of the form id.
     * {@link FormsConstants#REQUEST_PROPERTY_FORM_START} with the relative path to the form start par
     * and _charset_ with the value UTF-8
     *
     * @param request The current request.
     * @param response The current response.
     * @since 5.3
     * @throws IOException if form generation caused an error
     * @throws ServletException if form generation caused an error
     */
    public static void startForm(final SlingHttpServletRequest request,
                                 final SlingHttpServletResponse response)
    throws IOException, ServletException {
        // get resource and properties
        final Resource formResource = request.getResource();
        initialize(request, formResource, response);

        final ValueMap properties = ResourceUtil.getValueMap(formResource);
        String formId = properties.get("id", "");
        if(StringUtils.isEmpty(formId))
        	formId = getFormId(request);
        // write form element, we post to the same url we came from
        final PrintWriter out = response.getWriter();
        String url = request.getRequestURI();

        final String suffix = getActionSuffix(request);
        if (StringUtils.isNotBlank(suffix)) {
            url += (suffix.startsWith("/")) ? suffix : "/" + suffix;
        }

        SlingBindings bindings = (SlingBindings) request.getAttribute(SlingBindings.class.getName());
        XSSAPI xssAPI = bindings.getSling().getService(XSSAPI.class).getRequestSpecificAPI(request);
        String cssClass = properties.get("css", "");
        out.print("
"); // write form id as hidden field out.print(""); // write form start as hidden field out.print(""); // write charset as hidden field out.print(""); // check for redirect configuration String redirect = properties.get("redirect", ""); if ( redirect.length() > 0 ) { redirect = request.getResourceResolver().map(request, redirect); final int lastSlash = redirect.lastIndexOf('/'); if ( redirect.indexOf('.', lastSlash) == -1 ) { redirect = redirect + ".html"; } out.print(""); } writeJavaScript(request, response, formResource); // allow action to add form fields final String actionType = properties.get(FormsConstants.START_PROPERTY_ACTION_TYPE, ""); if (actionType.length() > 0) { runAction(actionType, "addfields", formResource, request, response); } } /** * Initialize the current request object. * Provide the required environment for form elements. * * @param request The current request. * @param formResource Resource. * @param response The current response. * @throws IOException if initialization caused an error * @throws ServletException if initialization caused an error */ private static void initialize(final SlingHttpServletRequest request, final Resource formResource, final SlingHttpServletResponse response) throws IOException, ServletException { final ValueMap properties = ResourceUtil.getValueMap(formResource); // set some "variables" final Boolean clientValidation = properties.get(FormsConstants.START_PROPERTY_CLIENT_VALIDATION, Boolean.FALSE); request.setAttribute(REQ_ATTR_CLIENT_VALIDATION, clientValidation); request.setAttribute(REQ_ATTR_FORMID, properties.get(FormsConstants.START_PROPERTY_FORMID, "new_form")); request.setAttribute(REQ_ATTR_IS_INIT, "true"); // now invoke init script for action (if response is set) if (response != null) { final String actionType = properties.get(FormsConstants.START_PROPERTY_ACTION_TYPE, FormsConstants.DEFAULT_ACTION_TYPE); if (actionType.length() != 0) { runAction(actionType, "init", formResource, request, response); } } // check for load path if ( request.getAttribute(REQ_ATTR_GLOBAL_LOAD_MAP) == null ) { Resource loadResource = null; final String loadPath = properties.get(FormsConstants.START_PROPERTY_LOAD_PATH, ""); if ( loadPath.length() > 0 ) { loadResource = formResource.getResourceResolver().getResource(loadPath); } FormsHelper.setFormLoadResource(request, loadResource); } } /** * Runs/includes a script of the form action. * * @param actionType action type * @param scriptName script name * @param formResource resource * @param request request * @param response response * @throws IOException if inclusion caused an error * @throws ServletException if inclusion caused an error */ public static void runAction(final String actionType, final String scriptName, final Resource formResource, final SlingHttpServletRequest request, final SlingHttpServletResponse response) throws IOException, ServletException { String rt = actionType; // eg. foundation/components/form/actions/TYPE if (actionType.indexOf('/') == -1) { rt = FormsConstants.RT_FORM_ACTION + "s/" + actionType; } final Resource includeResource = new ResourceWrapper(formResource, rt, FormsConstants.RST_FORM_ACTION); FormsHelper.includeResource(request, response, includeResource, scriptName); } /** * Check if the request is initialized. * This method checks if a form start has already been processed during this * request. The check is usually only required in author mode where a form * element might be requested directly (and not by a complete page reload). * @param request The current request. */ private static void checkInit(final SlingHttpServletRequest request) { if ( request.getAttribute(REQ_ATTR_IS_INIT) == null ) { // search the form start element FormStructureHelper formStructureHelper = (FormStructureHelper)request.getAttribute(REQ_ATTR_FORM_STRUCTURE_HELPER); formStructureHelper = formStructureHelper == null ? defaultFormStructureHelper : formStructureHelper; final Resource formStart = formStructureHelper.getFormResource(request.getResource()); try { initialize(request, formStart, null); } catch (IOException e) { // this can never happen } catch (ServletException e) { // this can never happen } } } /** * Check the type of the resource. * @return true if the type or super type is the given type. * @since 5.2 */ private static boolean checkResourceType(final Resource resource, final String type) { return ResourceUtil.isA(resource, type); } /** * Signal the end of the form. * @param req Request */ public static void endForm(final SlingHttpServletRequest req) { FormsHelper.setFormLoadResource(req, null); req.removeAttribute(REQ_ATTR_CLIENT_VALIDATION); req.removeAttribute(REQ_ATTR_FORMID); req.removeAttribute(REQ_ATTR_IS_INIT); } /** * Set the forward path for processing the form. * @param req The current request. * @param path The forward path. */ public static void setForwardPath(final SlingHttpServletRequest req, final String path) { setForwardPath(req, path, false); } /** * Set the forward path for processing the form and makes sure the "form" * selector from the form request is cleared upon forwarding. This is * usually required if the forward should go to the sling POST servlet, to * avoid conflicts with the form chooser. * *

* This is not required if the forward path already contains an extension * and possible selectors, in which case these overwrite the form request * selector anyway. * *

* * This uses * {@link #setForwardOptions(ServletRequest, RequestDispatcherOptions) * setForwardOptions} with * {@link RequestDispatcherOptions#setReplaceSelectors(String) * RequestDispatcherOptions.setReplaceSelectors("")}. * * @since 5.5 * * @param req * The current request. * @param path * The forward path. * @param clearFormSelector * if the "form" selector should be cleared */ public static void setForwardPath(final SlingHttpServletRequest req, final String path, final boolean clearFormSelector) { req.setAttribute(REQ_ATTR_FORWARD_PATH, path); if (clearFormSelector) { RequestDispatcherOptions options = new RequestDispatcherOptions(); options.setReplaceSelectors(""); setForwardOptions(req, options); } } /** * Get the forward path for processing the form. * @param req The current request. * @return The forward path or null. */ public static String getForwardPath(final SlingHttpServletRequest req) { return (String)req.getAttribute(REQ_ATTR_FORWARD_PATH); } /** * Sets the Sling {@link RequestDispatcherOptions} to be used when * forwarding to {@link #getForwardPath(SlingHttpServletRequest)}. * * @since 5.5 * * @param req * The current request * @param options * options to use with forward path */ public static void setForwardOptions(final ServletRequest req, final RequestDispatcherOptions options) { req.setAttribute(REQ_ATTR_FORWARD_OPTIONS, options); } /** * Gets the Sling {@link RequestDispatcherOptions} to be used when * forwarding to {@link #getForwardPath(SlingHttpServletRequest)}. * * @since 5.5 * * @param req * The current request * @return options to use with forward path or null */ public static RequestDispatcherOptions getForwardOptions(final ServletRequest req) { return (RequestDispatcherOptions) req.getAttribute(REQ_ATTR_FORWARD_OPTIONS); } /** * Sets the Sling POST serlvet's ":redirect" parameter dynamically during * the form POST execution, when * {@link #setForwardPath(SlingHttpServletRequest, String)} is used. * * @since 5.5 * * @param request * the current request * @param redirect * a redirect path/url */ public static void setForwardRedirect(final ServletRequest request, String redirect) { request.setAttribute(REQ_ATTR_REDIRECT, redirect); } /** * Returns the redirect to inject as ":redirect" parameter for the Sling * POST servlet, when a form * {@link #setForwardPath(SlingHttpServletRequest, String) forward} is done. * * @since 5.5 * * @param request * the current request * @return redirect path/url */ public static String getForwardRedirect(final ServletRequest request) { return (String) request.getAttribute(REQ_ATTR_REDIRECT); } /** * Set a request suffix to be added to the form action's URI. * @param req The current request. * @param suffix The suffix or null. */ public static void setActionSuffix(final SlingHttpServletRequest req, final String suffix) { req.setAttribute(REQ_ATTR_ACTION_SUFFIX, suffix); } /** * Get the request suffix currently set for the form action's URI. * @param req The current Request. * @return THe suffix or null. */ public static String getActionSuffix(final SlingHttpServletRequest req) { return (String) req.getAttribute(REQ_ATTR_ACTION_SUFFIX); } /** * Set the load resource for the form. * @param req The current request. * @param rsrc The load resource */ public static void setFormLoadResource(final SlingHttpServletRequest req, final Resource rsrc) { req.removeAttribute(REQ_ATTR_GLOBAL_LOAD_MAP); req.removeAttribute(REQ_ATTR_GLOBAL_LOAD_RESOURCE); if ( rsrc != null ) { req.setAttribute(REQ_ATTR_GLOBAL_LOAD_RESOURCE, rsrc); final ValueMap map = ResourceUtil.getValueMap(rsrc); req.setAttribute(REQ_ATTR_GLOBAL_LOAD_MAP, map); } } /** * Get the load resource for the form. * @param req current request * @return load resource or null if not set */ public static Resource getFormLoadResource(final SlingHttpServletRequest req) { return (Resource)req.getAttribute(REQ_ATTR_GLOBAL_LOAD_RESOURCE); } /** * Return the form values to load. * @param req The request * @return The values or null */ public static ValueMap getGlobalFormValues(final SlingHttpServletRequest req) { checkInit(req); return (ValueMap) req.getAttribute(REQ_ATTR_GLOBAL_LOAD_MAP); } /** * Sets the list of resources to be handled by the "edit" resources form action. * @param req current request * @param resources the list of resources */ public static void setFormEditResources(final SlingHttpServletRequest req, final List resources) { FormResourceEdit.setResources(req, resources); } /** * Get the list of resources to be handled by the "edit" resources form action. * @param req current request * @return the list of resources (or null if not set) */ public static List getFormEditResources(final SlingHttpServletRequest req) { return FormResourceEdit.getResources(req); } /** * Return the name of the check method. * Method name is based on from id with any hyphens converted to underscores. If the form can't be found, it will default to defaultForm. * @param req The current request. * @return The method name */ public static String getFormsPreCheckMethodName(final SlingHttpServletRequest req) { String formId = getFormId(req); SlingBindings bindings = (SlingBindings) req.getAttribute(SlingBindings.class.getName()); XSSAPI xssAPI = bindings.getSling().getService(XSSAPI.class).getRequestSpecificAPI(req); if (formId != null) { formId = xssAPI.getValidJSToken(formId, "defaultForm"); } return "cq5forms_preCheck_" + formId; } /** * Generate the java script */ private static void writeJavaScript(final SlingHttpServletRequest req, final SlingHttpServletResponse response, final Resource formResource) throws IOException, ServletException { if ( doClientValidation(req) ) { final PrintWriter out = response.getWriter(); // write form-specific java script out.println(""); } } /** * Include the resource with the given selector with method GET * @param request The current request. * @param response The current response. * @param resource The resource to include. * @param selectorString The selector string to use for inclusion. * @throws IOException if requested resource is not accessible * @throws ServletException if requested resource is not accessible */ public static void includeResource(final SlingHttpServletRequest request, final SlingHttpServletResponse response, final Resource resource, final String selectorString) throws IOException, ServletException { final Object oldValue = request.getAttribute(ComponentContext.BYPASS_COMPONENT_HANDLING_ON_INCLUDE_ATTRIBUTE); try { if(StringUtils.equals(selectorString, FormsConstants.SCRIPT_FORM_SERVER_VALIDATION)) { request.removeAttribute(ComponentContext.BYPASS_COMPONENT_HANDLING_ON_INCLUDE_ATTRIBUTE); } else { request.setAttribute(ComponentContext.BYPASS_COMPONENT_HANDLING_ON_INCLUDE_ATTRIBUTE, "true"); } final RequestDispatcherOptions options = new RequestDispatcherOptions(); options.setReplaceSelectors(selectorString); request.getRequestDispatcher(resource, options).include(request, response); } finally { if ( oldValue == null ) { request.removeAttribute(ComponentContext.BYPASS_COMPONENT_HANDLING_ON_INCLUDE_ATTRIBUTE); } else { request.setAttribute(ComponentContext.BYPASS_COMPONENT_HANDLING_ON_INCLUDE_ATTRIBUTE, oldValue); } } } /** * Are we generating client validation? * @param req Request * @return true or false */ public static boolean doClientValidation(final SlingHttpServletRequest req) { checkInit(req); Boolean value = (Boolean)req.getAttribute(REQ_ATTR_CLIENT_VALIDATION); if ( value == null ) { value = Boolean.FALSE; } return value.booleanValue(); } /** * Return the formid * @param req Request * @return The form id or null */ public static String getFormId(final SlingHttpServletRequest req) { checkInit(req); return (String)req.getAttribute(REQ_ATTR_FORMID); } /** * Return the parameter name for the field * @param rsrc The resource * @return The parameter name. */ public static String getParameterName(final Resource rsrc) { final ValueMap properties = ResourceUtil.getValueMap(rsrc); String name = properties.get(FormsConstants.ELEMENT_PROPERTY_NAME, ""); if ( name.length() == 0 ) { name = ResourceUtil.getName(rsrc); name = FormsUtil.filterElementName(name); } return name; } /** * Return the id for the field * @param req The current request. * @param rsrc The resource. * @return The id. */ public static String getFieldId(final SlingHttpServletRequest req, final Resource rsrc) { return getFormId(req) + '_' + getParameterName(rsrc); } /** * Return all form elements for this form. * @param formResource The form resource- * @return An iterator for all form elements. * * @deprecated use {@link FormStructureHelper#getFormElements(Resource)} instead. */ @Deprecated public static Iterator getFormElements(final Resource formResource) { return defaultFormStructureHelper.getFormElements(formResource).iterator(); } /** * Return a list of content fields. * This method returns all field names (= request parameter names) that contain actually content * by filtering out special request parameters like those starting with a ":", "_charset_" etc. * @return Iterator for the field names. */ public static Iterator getContentRequestParameterNames(final SlingHttpServletRequest req) { final List names = new ArrayList(); @SuppressWarnings("unchecked") final Enumeration paramNames = req.getParameterNames(); while (paramNames.hasMoreElements() ) { final String name = paramNames.nextElement(); if ( !name.startsWith(":") && !name.equals("_charset_") ) { names.add(name); } } return names.iterator(); } /** * Returns a resource identified by a path relative to the * elementResource. This method also considers form edit * resources. * * @param request the current request. * @param elementResource the element resource. * @param relPath a path relative to elementResource. * @return the resource or null if none exists at the given * relPath. */ public static Resource getResource(SlingHttpServletRequest request, Resource elementResource, String relPath) { List resources = new ArrayList(); // consider edit resources if any List editRes = FormResourceEdit.getResources(request); if (editRes != null) { resources.addAll(editRes); } // then element resource resources.add(elementResource); ResourceResolver resolver = request.getResourceResolver(); for (Resource r : resources) { Resource res = resolver.getResource(r, relPath); if (res != null) { return res; } } return null; } /** * Return the value for the element. * This method invokes {@link #getValues(SlingHttpServletRequest, Resource)} and returns * if available the first value from the array. * @param request The current request. * @param elementResource The element resource. * @return The value for the form element or null. */ public static String getValue(final SlingHttpServletRequest request, final Resource elementResource) { return getValue(request, elementResource, null); } /** * Return the value for the element. * This method invokes {@link #getValues(SlingHttpServletRequest, Resource)} and returns * if available the first value from the array. * @param request The current request. * @param elementResource The element resource. * @param nameParam The name of the name parameter (defaults to "name") * @return The value for the form element or null. */ public static String getValue(final SlingHttpServletRequest request, final Resource elementResource, final String nameParam) { final String[] values = getValues(request, elementResource, nameParam); if ( values != null && values.length > 0 ) { return values[0]; } return null; } /** * Return the values for the element. * This method * @param request The current request. * @param elementResource The element resource. * @return The values for the form element or null. */ public static String[] getValues(final SlingHttpServletRequest request, final Resource elementResource) { return getValues(request, elementResource, null); } /** * Return the values for the element. * This method * @param request The current request. * @param elementResource The element resource. * @param nameParam The name of the name parameter (defaults to "name") * @return The values for the form element or null. */ public static String[] getValues(final SlingHttpServletRequest request, final Resource elementResource, final String nameParam) { final ValueMap properties = ResourceUtil.getValueMap(elementResource); final String name = nameParam != null ? nameParam : getParameterName(elementResource); // if we have validation errors we will use the old value! final ValidationInfo info = ValidationInfo.getValidationInfo(request); if ( info != null ) { return info.getValues(name); } // globally defined form values final ValueMap globalFormValues = FormsHelper.getGlobalFormValues(request); // get the default value // this can either be an old value, a constant or a property from the repository String[] defaultValues = null; final String loadPath = properties.get(FormsConstants.ELEMENT_PROPERTY_LOAD_PATH, ""); if ( loadPath.length() > 0 ) { // check if loadPath is defined and // first try this as an absolut path // second try this as a property in the global values final Resource rsrc = request.getResourceResolver().getResource(loadPath); if ( rsrc != null ) { defaultValues = rsrc.adaptTo(String[].class); } else if ( globalFormValues != null && globalFormValues.get(loadPath) != null ) { defaultValues = globalFormValues.get(loadPath, String[].class); } } else if ( globalFormValues != null && globalFormValues.get(name) != null ) { defaultValues = globalFormValues.get(name, String[].class); } // if we don't have values yet, get default values if ( defaultValues == null ) { defaultValues = properties.get(FormsConstants.ELEMENT_PROPERTY_DEFAULT_VALUE, String[].class); } return defaultValues; } /** * Return the values for the element as a list * This method * @param request The current request. * @param elementResource The element resource. * @return The values for the form element or an empty list. */ public static List getValuesAsList(final SlingHttpServletRequest request, final Resource elementResource) { final String[] values = getValues(request, elementResource); if ( values == null ) { return Collections.emptyList(); } return Arrays.asList(values); } /** * Returns the value for the given name (property). * @param request The current request * @param name name of the property (or property path) * @param defaultValue default value to return if property is not present * @return The value for the given property */ public static String getValue(final SlingHttpServletRequest request, final String name, final String defaultValue) { String[] values = getValues(request, name, null); if (values == null || values.length == 0) { return defaultValue; } return values[0]; } /** * Returns the values for the given name (property). * @param request The current request * @param name name of the property (or property path) * @param defaultValues default values to return if property is not present * @return The values for the given property */ public static String[] getValues(final SlingHttpServletRequest request, final String name, final String[] defaultValues) { final ValueMap globalFormValues = FormsHelper.getGlobalFormValues(request); if (globalFormValues == null || globalFormValues.get(name) == null) { return defaultValues; } return globalFormValues.get(name, String[].class); } /** * Writes the given form load resource as JSON into the given writer. This * will dump the full tree; use * {@link #inlineValuesAsJson(SlingHttpServletRequest, Writer, String, int)} * for controlling the node depth. * *

* Can be used in JSPs to inline JSON for javascript code, for example: * *

     * var data = <% FormsHelper.inlineValuesAsJson(slingRequest, out, "."); %>;
     * 
* * which might result in: * *
     * var data = { "jcr:primaryType": "nt:unstructured", "property" : "value" };
     * 
* *

* If the path cannot be found, an empty object "{}" will be * written. Any exception will be passed to the caller. * *

* The underlying form load resource must be based on a JCR Node. The path * is relative and allows to specify subnodes. It cannot point to JCR * properties, please use * {@link #getValue(SlingHttpServletRequest, String, String)} or * {@link #getValues(SlingHttpServletRequest, String, String[])} for them. * * @param request * the current request * @param out * a writer, such as a {@link JspWriter}, to write the JSON into. * Will automatically be flushed before and after. * @param path * an absolute node path or a node path relativ to the current * form load resource. Use "." for the resource node itself. * @throws RepositoryException * if some jcr error happened * @throws JSONException * if writing the json failed * @throws IOException * if there was a problem with the writer */ public static void inlineValuesAsJson(final SlingHttpServletRequest request, Writer out, String path) throws IOException, RepositoryException, JSONException { inlineValuesAsJson(request, out, path, -1); } /** * Writes the given form load resource as JSON into the given writer. Can be * used in JSPs to inline JSON for javascript code, for example: * *

     * var data = <% FormsHelper.inlineValuesAsJson(slingRequest, out, "."); %>;
     * 
* * which might result in: * *
     * var data = { "jcr:primaryType": "nt:unstructured", "property" : "value" };
     * 
* *

* If the path cannot be found, an empty object "{}" will be * written. Any exception will be passed to the caller. * *

* The underlying form load resource must be based on a JCR Node. The path * is relative and allows to specify subnodes. It cannot point to JCR * properties, please use * {@link #getValue(SlingHttpServletRequest, String, String)} or * {@link #getValues(SlingHttpServletRequest, String, String[])} for them. * * @param request * the current request * @param out * a writer, such as a {@link JspWriter}, to write the JSON into. * Will automatically be flushed before and after. * @param path * an absolute node path or a node path relativ to the current * form load resource. Use "." for the resource node itself. * @param nodeDepth * until which depth the tree should be written; 0 means the * current node and its properties only; -1 means the whole tree. * @throws RepositoryException * if some jcr error happened * @throws JSONException * if writing the json failed * @throws IOException * if there was a problem with the writer */ public static void inlineValuesAsJson(final SlingHttpServletRequest request, Writer out, String path, int nodeDepth) throws IOException, RepositoryException, JSONException { out.flush(); Node node; Session session = request.getResourceResolver().adaptTo(Session.class); if (path.startsWith("/")) { if (session.nodeExists(path)) { node = session.getNode(path); } else { // write empty object to not break javascript syntax out.append("{}"); return; } } else { Resource loadResource = FormsHelper.getFormLoadResource(request); if (loadResource == null) { out.append("{}"); return; } node = loadResource.adaptTo(Node.class); if (node == null) { out.append("{}"); return; } if (!node.hasNode(path)) { out.append("{}"); return; } node = node.getNode(path); } JsonItemWriter jsonWriter = new JsonItemWriter(null); jsonWriter.dump(node, new PrintWriter(out), nodeDepth); out.flush(); } /** * Recurse down a subtree collecting all showHideExpressions into a map keyed by element name. * * @param node the node to check for showHideExpressions. * @param map a collection of node names, and their associated showHideExpression. * @throws RepositoryException if repository access caused an error */ private static void accumulateShowHideExpressions(final Node node, Map map) throws RepositoryException { if (node.hasProperty("showHideExpression")) { map.put(node.hasProperty("name") ? node.getProperty("name").getString() : node.getName(), node.getProperty("showHideExpression").getString()); } for (NodeIterator iterator = node.getNodes(); iterator.hasNext();) { accumulateShowHideExpressions(iterator.nextNode(), map); } } /** * Return a flattened map of all showHideExpressions that are descendants of a resource. * * @param resource the node to check to see if there's any showHideExpressions. * @return A map of showHideExpressions keyed by element name. * @throws RepositoryException if repository access caused an error */ public static Map getShowHideExpressions(final Resource resource) throws RepositoryException { Node node = resource.adaptTo(Node.class); Map map = new HashMap(); accumulateShowHideExpressions(node, map); return map; } /** * Return the options for a form element * @param request request * @param elementResource element * @return A map of options (key-value) or null. */ public static Map getOptions(final SlingHttpServletRequest request, final Resource elementResource) { final ValueMap properties = ResourceUtil.getValueMap(elementResource); String[] options = null; final String loadPath = properties.get(FormsConstants.ELEMENT_PROPERTY_OPTIONS_LOAD_PATH, ""); if ( loadPath.length() > 0 ) { // check if loadPath is defined and try this as an absolut path final Resource rsrc = request.getResourceResolver().getResource(loadPath); if ( rsrc != null ) { options = rsrc.adaptTo(String[].class); } } // if we don't have values yet, get default values if ( options == null ) { options = properties.get(FormsConstants.ELEMENT_PROPERTY_OPTIONS, String[].class); } if ( options == null ) { return null; } // now split into key value final Map splitValues = new java.util.LinkedHashMap(); for(int i=0; i 0 ) { boolean endLoop = true; int pos = -1; int start = 0; do { pos = value.indexOf('=', start); // check for escaping if ( pos > 0 && value.charAt(pos-1) == '\\' ) { start = pos +1; endLoop = false; } else { endLoop = true; } } while ( !endLoop); String v, t; if ( pos == -1 ) { v = value; t = value; } else { v = value.substring(0, pos); t = value.substring(pos+1); } v = v.replace("\\=", "="); t = t.replace("\\=", "="); splitValues.put(v, t); } else { splitValues.put("", ""); } } if ( splitValues.size() == 0 ) { return null; } return splitValues; } /** * Is this field required? * @param formElement The form element. * @return true if the field is required, false otherwise. */ public static boolean isRequired(final Resource formElement) { final ValueMap properties = ResourceUtil.getValueMap(formElement); return properties.get(FormsConstants.ELEMENT_PROPERTY_REQUIRED, Boolean.FALSE); } /** * Marks the current form rendering to produce an read-only form. Form field * renderings must use * {@link #isReadOnly(SlingHttpServletRequest, Resource)} to decide between * edit or read-only representations. * * @param request * the current request */ public static void setFormReadOnly(final SlingHttpServletRequest request) { request.setAttribute(REQ_ATTR_READ_ONLY, true); } /** * Push a temporary read-only state. (See {@link #setFormReadOnly(SlingHttpServletRequest)} * for further details of read-only states.) * * @param request the current request * @return a token for use by {@link #popFormReadOnly(SlingHttpServletRequest, Object)} */ public static Object pushFormReadOnly(final SlingHttpServletRequest request) { boolean previousState = isReadOnly(request); request.setAttribute(REQ_ATTR_READ_ONLY, true); return previousState; } /** * Pop a temporary read-only state. * @param request the current request * @param previousState The token returned by {@link #pushFormReadOnly(SlingHttpServletRequest)} */ public static void popFormReadOnly(final SlingHttpServletRequest request, Object previousState) { if (!((Boolean) previousState)) { request.removeAttribute(REQ_ATTR_READ_ONLY); } } /** * Returns true if either the passed form field is configured as read-only * or if the entire form is to be displayed in a read-only way. The latter * is the case when {@link #setFormReadOnly(SlingHttpServletRequest)} was * called, for example if the "view" selector of the * {@link FormChooserServlet} is used. * * @param request * the current request * @param formElement * the form field resource * @return true if this field is to be rendered as read-only, * false otherwise. */ public static boolean isReadOnly(final SlingHttpServletRequest request, Resource formElement) { if (request.getAttribute(REQ_ATTR_READ_ONLY) != null) { return true; } ValueMap properties = ResourceUtil.getValueMap(formElement); return properties.get(FormsConstants.ELEMENT_PROPERTY_READ_ONLY, Boolean.FALSE); } /** * Returns true if the entire form has to be displayed in a read-only way. * @param request * the current request * @return true if a form element has to be rendered as read-only, * false otherwise. * @since 5.5 */ public static boolean isReadOnly(final SlingHttpServletRequest request) { return request.getAttribute(REQ_ATTR_READ_ONLY) != null; } /** * Returns true if the passed form field is configured as read-only. This is * determined solely by looking at the field's "readOnly" property. * * @deprecated * To always support the global read-only flag, set for example by the * "view" selector of the {@link FormChooserServlet}, use * {@link #isReadOnly(SlingHttpServletRequest, Resource)} instead. * * @param formElement * the form field resource * @return true if this field is read-only, false * otherwise. */ @Deprecated public static boolean isReadOnly(Resource formElement) { ValueMap properties = ResourceUtil.getValueMap(formElement); return properties.get(FormsConstants.ELEMENT_PROPERTY_READ_ONLY, Boolean.FALSE); } /** *

Checks the rule specified by the given form property.

*

Rules may be used to enable/disable form elements according to some serverside * conditions.

*

Currently, only rules depending on access rights are available.

* @param resource resource * @param req request * @param propName property name * @return true if check was successful */ public static boolean checkRule(final Resource resource, final SlingHttpServletRequest req, final PageContext pageContext, String propName) { ValueMap valueMap = ResourceUtil.getValueMap(resource); String rule = valueMap.get(propName, (String) null); if (rule == null) { return true; } rule = ELEvaluator.evaluate(rule, req, pageContext); final String[] ruleParts = rule.split(":"); if (ruleParts.length < 2) { return true; } if (ruleParts[0].equals("access")) { if (ruleParts.length != 3) { return true; } final String path = ruleParts[1]; final String permission = ruleParts[2]; try { final Node node = resource.adaptTo(Node.class); final Session session = node.getSession(); session.checkPermission(path, permission); // SecurityUtil.hasPermissionOn(node.getSession(), privilege, path); } catch (AccessControlException ace) { return false; } catch (RepositoryException re) { LOGGER.error("Could not determine access rights for path '" + path + "'", re); return false; } } return true; } /** * Return the title for the field. * @param formElement The form element. * @param defaultTitle The default title. * @return The title to display. */ public static String getTitle(final Resource formElement, String defaultTitle) { final ValueMap properties = ResourceUtil.getValueMap(formElement); return properties.get(JcrConstants.JCR_TITLE, defaultTitle); } /** * Return the description for the field. * @param formElement The form element. * @param defaultDescription The default description. * @return The description to display. */ public static String getDescription(final Resource formElement, String defaultDescription) { final ValueMap properties = ResourceUtil.getValueMap(formElement); return properties.get(JcrConstants.JCR_DESCRIPTION, defaultDescription); } /** * Is this a field with multi selection? * @param formElement The form element * * @since 5.5 * @return true if field has multi selection */ public static boolean hasMultiSelection(final Resource formElement) { final ValueMap properties = ResourceUtil.getValueMap(formElement); return properties.get(FormsConstants.ELEMENT_PROPERTY_MULTI_SELECTION, Boolean.FALSE); } /** * Redirect to the referrer. * This method redirects to the referrer and adds optional request parameters. * @param req The current request * @param res The current response * @throws IOException if redirection caused an error */ public static void redirectToReferrer(final SlingHttpServletRequest req, final SlingHttpServletResponse res, final Map params) throws IOException { final String referrer = getReferrer(req); if ( params != null && params.size() > 0 ) { final StringBuilder buffer = new StringBuilder(referrer); boolean hasParams = referrer.indexOf('?') > 0; for(final Map.Entry entry : params.entrySet()) { for(final String value : entry.getValue() ) { buffer.append(hasParams ? '&' : '?'); hasParams = true; buffer.append(entry.getKey()); buffer.append('='); buffer.append(URLEncoder.encode(value, "utf-8")); } } res.sendRedirect(buffer.toString()); } else { res.sendRedirect(referrer); } } /** * Redirect to the referrer. This method redirects to the referrerand copies * the request parameters. * * @param request The current request * @param res The current response * @since 5.2 * @throws IOException if redirection caused an error */ public static void redirectToReferrer(final SlingHttpServletRequest request, final SlingHttpServletResponse res) throws IOException { String referrer = getReferrer(request); final int pos = referrer.indexOf('?'); if (pos > 0) { referrer = referrer.substring(0, pos); } final StringBuilder buffer = new StringBuilder(referrer); final RequestParameterMap params = request.getRequestParameterMap(); if (params.entrySet().size() > 0) { buffer.append("?"); boolean first = true; final Iterator> entryIter = params.entrySet().iterator(); while (entryIter.hasNext()) { final Map.Entry current = entryIter.next(); final RequestParameter[] values = current.getValue(); for (int i = 0; i < values.length; i++) { if (first) { first = false; } else { buffer.append("&"); } buffer.append(current.getKey()); buffer.append("="); buffer.append(values[i].getString()); } } } res.sendRedirect(buffer.toString()); } /** * Fix the form. * When a form start is added, add automatically a forms end (if missing) * When only a form end is on the page remove it * @since 5.2 * @deprecated use {@link FormStructureHelper#updateFormStructure(Resource)} instead. */ @Deprecated public static Resource checkFormStructure(final Resource rsrc) { return defaultFormStructureHelper.updateFormStructure(rsrc); } /** * Url encode the value. * The value is encoded with character set UTF-8. * @param value The value * @return The encoded value. * @since 5.2 */ public static String encodeValue(String value) { try { return URLEncoder.encode(value, "UTF-8"); } catch (UnsupportedEncodingException e) { // utf-8 is always supported, but let's return something anyway... return value; } } /** * Url decode the value. * The value is decoded with character set UTF-8. * @param value The value * @return The decoded value. * @since 5.2 */ public static String decodeValue(String value) { try { return URLDecoder.decode(value, "UTF-8"); } catch (UnsupportedEncodingException e) { // utf-8 is always supported, but let's return something anyway... return value; } } /** * Return the css classes for the field. * If the field has a property {@link FormsConstants#ELEMENT_PROPERTY_CSS} * the value of this property is appended to the default css. If not, only the * default css is returned. * @param props The field properties. * @param defaultCss The default css for this field. * @return The css classes * * @since 5.4 */ public static String getCss(final ValueMap props, final String defaultCss) { final String configCss = props.get(FormsConstants.ELEMENT_PROPERTY_CSS, null); if ( configCss == null ) { return defaultCss; } return defaultCss + ' ' + StringEscapeUtils.escapeHtml4(configCss); } /** * Returns the HTTP "referrer" header from the request, and also looks out * for the common "referer" misspelling. * * @since 5.5 * * @param request * current request * @return value of the referrer header or null if not present */ public static String getReferrer(HttpServletRequest request) { return request.getHeader("Referer") != null ? request.getHeader("Referer") : request.getHeader("Referrer"); } /** * Sets a flag to redirect to the HTTP referrer after the forward of a form * POST request. This will usually only be used if no explicit redirect is * already given in the ":redirect" parameter used by the Sling POST servlet. * * @since 5.5 * * @param request * current request * @param redirectToReferrer * true to enable the redirect to the referrer */ public static void setRedirectToReferrer(ServletRequest request, boolean redirectToReferrer) { if (redirectToReferrer) { request.setAttribute(REQ_ATTR_REDIRECT_TO_REFERRER, "true"); } else { request.removeAttribute(REQ_ATTR_REDIRECT_TO_REFERRER); } } /** * Returns whether there should be a redirect to the HTTP referrer after the * forward of a form POST request. * * @since 5.5 * * @param request * current request * @return true if there should be a redirect to the referrer */ public static boolean isRedirectToReferrer(ServletRequest request) { return "true".equals(request.getAttribute(REQ_ATTR_REDIRECT_TO_REFERRER)); } /** * Returns the locale. * If the request originates from a jsp, it returns the locale as defined * by the {@link com.day.cq.wcm.api.LanguageManager}, otherwise it returns * null * @param request The current request * @return the locale or null if not determinable */ public static Locale getLocale(SlingHttpServletRequest request) { SlingBindings bindings = (SlingBindings) request.getAttribute(SlingBindings.class.getName()); if (bindings == null) { LOGGER.debug("The request does not provide a SlingBindings attribute: the method returns null."); return null; } SlingScriptHelper scriptHelper = bindings.getSling(); LanguageManager langMgr = scriptHelper.getService(LanguageManager.class); if (langMgr == null) { LOGGER.debug("The LanguageManager service is not available: the method returns null."); return null; } Resource resource = request.getResource(); Locale locale = langMgr.getLanguage(resource); return locale; } /** * Returns the localized message. * If the request originates from a jsp, it returns the localized message * based on the {@link java.util.ResourceBundle} of the request and the * locale defined by the {@link com.day.cq.wcm.api.LanguageManager}. * Otherwise it returns the original message. * @param msg The message to be localized * @param request The current request * @return the localized message or the original message if it cannot be localized */ public static String getLocalizedMessage(String msg, SlingHttpServletRequest request) { Locale locale = getLocale(request); ResourceBundle resBundle = request.getResourceBundle(locale); if (resBundle == null || msg == null || resBundle.getString(msg) == null) { LOGGER.debug("The message cannot be localized: the method returns the original message."); return msg; } return resBundle.getString(msg); } /** * Get the list of white listed data name patterns. * @param req The current request. * @return The array of white listed data name patterns */ public static String[] getWhitelistPatterns(final SlingHttpServletRequest req) { return (String[])req.getAttribute(REQ_ATTR_PROP_WHITELIST); } /** * Indicates whether posted form values should be passed through an expression evaluator. It will be up to * each component to decide how it react to this attribute. * @param req The current request. * @return true if expressions should be evaluated on posted values */ public static boolean allowExpressions(final SlingHttpServletRequest req) { Boolean expressionsEnabledAttr = (Boolean) req.getAttribute(REQ_ATTR_EXPRESSIONS_ENABLED); if (expressionsEnabledAttr == null) { return true; } else { return expressionsEnabledAttr.booleanValue(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy