com.day.cq.wcm.foundation.forms.FieldHelper.java Source code

Java tutorial

Introduction

Here is the source code for com.day.cq.wcm.foundation.forms.FieldHelper.java

Source

/*
 * Copyright 1997-2009 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 javax.servlet.ServletException;

import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.sling.api.SlingException;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;

import com.day.cq.wcm.foundation.forms.impl.FormsHandlingResponse;
import com.day.cq.wcm.foundation.forms.impl.ResourceWrapper;

/**
 * Helper class for the field components.
 * @since 5.3
 */
public class FieldHelper {

    private FieldHelper() {
        // no instances
    }

    /** Request attribute prefix for description cache. */
    private static final String ATTR_CACHE = FieldHelper.class.getName() + "/Cache";
    /** Request attribute prefix for init flag. */
    private static final String ATTR_INIT = FieldHelper.class.getName() + "/Init";
    /** Request attribute for the current field description. */
    private static final String ATTR_DESC = FieldHelper.class.getName() + "/CurrentDesc";

    /**
     * Get the attribute name for the cache entry.
     */
    private static String getCacheAttrName(final Resource rsrc) {
        return ATTR_CACHE + rsrc.getPath();
    }

    /**
     * Get the attribute name for the init flag.
     */
    private static String getInitAttrName(final Resource rsrc) {
        return ATTR_INIT + rsrc.getPath();
    }

    /**
     * Create a default field description for the field.
     * This methods creates a new field description via
     * {@link FieldDescription#FieldDescription(Resource)}
     * and associates this with the resource.
     * If this method is invoked twice for the same resource
     * and request combination, the default description is
     * added twice as well!
     *
     * @param req  The current request.
     * @param rsrc The field resource.
     * @return The new field description.
     */
    public static FieldDescription createDefaultDescription(final SlingHttpServletRequest req,
            final Resource rsrc) {
        final FieldDescription desc = new FieldDescription(rsrc);
        desc.update(rsrc);
        addDescription(req, desc);
        return desc;
    }

    /**
     * Add a field description for the field.
     *
     * @param req  The current request.
     * @param desc The new field description.
     */
    public static void addDescription(final SlingHttpServletRequest req, final FieldDescription desc) {
        final String key = getCacheAttrName(desc.getFieldResource());
        FieldDescription[] descs = (FieldDescription[]) req.getAttribute(key);
        if (descs == null) {
            descs = new FieldDescription[] { desc };
        } else {
            FieldDescription[] newDescs = new FieldDescription[descs.length + 1];
            System.arraycopy(descs, 0, newDescs, 0, descs.length);
            newDescs[descs.length] = desc;
            descs = newDescs;
        }
        req.setAttribute(key, descs);
    }

    /**
     * Return all field descriptions associated with this field.
     * @param req  The current request.
     * @param rsrc The field resource.
     * @return The descriptions for this field.
     */
    public static FieldDescription[] getFieldDescriptions(final SlingHttpServletRequest req, final Resource rsrc) {
        final String key = getCacheAttrName(rsrc);
        FieldDescription[] descs = (FieldDescription[]) req.getAttribute(key);
        if (descs == null) {
            descs = new FieldDescription[] { createDefaultDescription(req, rsrc) };
        }
        return descs;
    }

    /**
     * Call the initialize script for the field.
     * @param req The current request.
     * @param res The current response.
     * @param rsrc The field resource.
     */
    public static void initializeField(final SlingHttpServletRequest req, final SlingHttpServletResponse res,
            final Resource rsrc) throws ServletException, IOException {
        initField(req, res, rsrc);
    }

    /**
     * Get the full qualified path to the field to be used in client java script.
     */
    public static String getClientFieldQualifier(final SlingHttpServletRequest request,
            final FieldDescription desc) {
        return getClientFieldQualifier(request, desc, "");
    }

    /**
     * Get the full qualified path to a suffixed field (e.g. @Write) to be used in client java script.
     * @param request The request
     * @param desc The field descritpion
     * @param suffix The suffix
     * @return The qualified path
     * @since 5.5
     */
    public static String getClientFieldQualifier(SlingHttpServletRequest request, FieldDescription desc,
            String suffix) {
        final String formId = FormsHelper.getFormId(request);
        return "document.forms[\"" + StringEscapeUtils.escapeEcmaScript(formId) + "\"]" + ".elements[\""
                + desc.getName() + suffix + "\"]";
    }

    /**
     * Return the current field description.
     * This method can be used by constraints to get the current
     * field description.
     * @return The current field description.
     */
    public static FieldDescription getConstraintFieldDescription(final SlingHttpServletRequest req) {
        FieldDescription desc = (FieldDescription) req.getAttribute(ATTR_DESC);
        if (desc == null) {
            desc = new FieldDescription(req.getResource());
            desc.update(req.getResource());
        }
        return desc;
    }

    /**
     * Write the client java script code to check a required field on
     * form submit.
     */
    public static void writeClientRequiredCheck(final SlingHttpServletRequest request,
            final SlingHttpServletResponse response, final FieldDescription desc) throws IOException {
        final String formId = FormsHelper.getFormId(request);
        if (desc.isRequired()) {
            final PrintWriter out = response.getWriter();
            final String qualifier = getClientFieldQualifier(request, desc);
            out.write("if (cq5forms_isEmpty(");
            out.write(qualifier);
            out.write(")) {cq5forms_showMsg('");
            out.write(StringEscapeUtils.escapeEcmaScript(formId));
            out.write("','");
            out.write(StringEscapeUtils.escapeEcmaScript(desc.getName()));
            out.write("','");
            out.write(StringEscapeUtils.escapeEcmaScript(desc.getRequiredMessage()));
            out.write("'); return false; }\n");
        }
    }

    /**
     * Return the error message for the constraint of the field.
     * If the field description has a constraint message, this message is used,
     * if not a default constraint message is looked up from the constraint
     * resource. If no such message is available, "Field is not valid" is
     * used as the message.
     *
     * @param desc The field description.
     * @param request The current request.
     * @return The constraint error message.
     */
    public static String getConstraintMessage(final FieldDescription desc, final SlingHttpServletRequest request) {
        String msg = desc.getConstraintMessage();
        if (msg == null) {
            final ResourceResolver resourceResolver = request.getResourceResolver();
            int index = 0;
            final String[] paths = resourceResolver.getSearchPath();
            while (index < paths.length && msg == null) {
                final String scriptPath = paths[index] + request.getResource().getResourceType();
                try {
                    final Resource scriptResource = resourceResolver.getResource(scriptPath);
                    if (scriptResource != null) {
                        // check for a default message from constraint
                        final ValueMap props = ResourceUtil.getValueMap(scriptResource);
                        msg = props.get(FormsConstants.COMPONENT_PROPERTY_CONSTRAINT_MSG, String.class);
                    }
                } catch (SlingException se) {
                    // we ignore this!
                }
                index++;
            }
            if (msg == null) {
                msg = "Field is not valid.";
            }
        }
        return msg;
    }

    /**
     * Write client regexp text.
     */
    public static void writeClientRegexpText(final SlingHttpServletRequest request,
            final SlingHttpServletResponse response, final FieldDescription desc, final String regexp)
            throws IOException {
        final PrintWriter out = response.getWriter();
        final String id = getClientFieldQualifier(request, desc);
        out.write("{var obj =");
        out.write(id);
        out.write(";" + "if ( cq5forms_isArray(obj)) {" + "for(i=0;i<obj.length;i++) {"
                + "if (!cq5forms_regcheck(obj[i].value, ");
        out.write(regexp);
        out.write(")) {" + "cq5forms_showMsg('");
        out.write(FormsHelper.getFormId(request));
        out.write("','");
        out.write(desc.getName());
        out.write("','");
        out.write(getConstraintMessage(desc, request));
        out.write("', i); return false;}}} else {" + "if (!cq5forms_regcheck(obj.value, ");
        out.write(regexp);
        out.write(")) {" + "cq5forms_showMsg('");
        out.write(StringEscapeUtils.escapeEcmaScript(FormsHelper.getFormId(request)));
        out.write("','");
        out.write(StringEscapeUtils.escapeEcmaScript(desc.getName()));
        out.write("','");
        out.write(StringEscapeUtils.escapeEcmaScript(getConstraintMessage(desc, request)));
        out.write("'); return false;}}}");
    }

    /**
     * Write the client java script code to check a constraint on
     * form submit.
     */
    public static void writeClientConstraintCheck(final SlingHttpServletRequest request,
            final SlingHttpServletResponse response, final FieldDescription desc)
            throws IOException, ServletException {
        if (desc.getConstraintType() != null) {
            final PrintWriter out = response.getWriter();
            final String qualifier = getClientFieldQualifier(request, desc);
            out.write("if (!cq5forms_isEmpty(");
            out.write(qualifier);
            out.write(")){");
            try {
                request.setAttribute(ATTR_DESC, desc);
                final Resource includeResource = new ResourceWrapper(desc.getFieldResource(),
                        desc.getConstraintType(), FormsConstants.RST_FORM_CONSTRAINT);

                FormsHelper.includeResource(request, response, includeResource,
                        FormsConstants.SCRIPT_CLIENT_VALIDATION);
                out.write("}");
            } finally {
                request.removeAttribute(ATTR_DESC);
            }
        }
    }

    /**
     * Convenience method to check the constraint of a field element.
     * If the field has a constraint and is not empty, the constraint is checked.
     *
     * @param request The current request.
     * @param response The current response.
     * @param desc The field description.
     */
    public static void checkConstraint(final SlingHttpServletRequest request,
            final SlingHttpServletResponse response, final FieldDescription desc)
            throws IOException, ServletException {
        // we evaluate the constraint only if the field is not null
        if (!isEmpty(request, desc.getName()) && doValidation(request, desc)) {
            // additional constraint?
            if (desc.getConstraintType() != null) {
                try {
                    request.setAttribute(ATTR_DESC, desc);
                    final Resource includeResource = new ResourceWrapper(desc.getFieldResource(),
                            desc.getConstraintType(), FormsConstants.RST_FORM_CONSTRAINT);
                    FormsHelper.includeResource(request, response, includeResource,
                            FormsConstants.SCRIPT_SERVER_VALIDATION);
                } finally {
                    request.removeAttribute(ATTR_DESC);
                }
            }
        }
    }

    /**
     * Convenience method to check the required flag of a field element.
     * @param request The current element.
     * @return true if check passed.
     */
    public static boolean checkRequired(final SlingHttpServletRequest request, final FieldDescription desc) {
        // required is checked first
        if (desc.isRequired() && isEmpty(request, desc.getName()) && doValidation(request, desc)) {
            ValidationInfo.createValidationInfo(request).addErrorMessage(desc.getName(), desc.getRequiredMessage());
            return false;
        }
        return true;
    }

    /**
     * Determine if the field has to be validated. If no or a single post resources
     * is defined the field is always validated. Multiple post resources are only
     * validated when the @Write parameter is set.
     * is set
     */
    private static boolean doValidation(SlingHttpServletRequest request, FieldDescription desc) {
        return request.getParameter(desc.getName() + FormResourceEdit.WRITE_SUFFIX) != null
                || FormResourceEdit.isSingleResourcePost(request);
    }

    /**
     * Private method to initialize the field.
     */
    private static void initField(final SlingHttpServletRequest req, final SlingHttpServletResponse res,
            final Resource rsrc) throws ServletException, IOException {
        final String key = getInitAttrName(rsrc);
        final Object flag = req.getAttribute(key);
        if (flag == null) {
            req.setAttribute(key, Boolean.TRUE);
            FormsHelper.includeResource(req, new FormsHandlingResponse(res), rsrc,
                    FormsConstants.SCRIPT_FIELD_INIT);
        }
    }

    /**
     * Checks if the request contains any parameter value of the given name, i.e.
     * either if a single value paramter is not emtpy or if multi value parameters
     * contain at least one value.
     * @param request
     * @param name
     * @return
     */
    private static boolean isEmpty(SlingHttpServletRequest request, String name) {
        String[] values = request.getParameterValues(name);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                if (values[i].trim().length() > 0) {
                    return false;
                }
            }
        }
        return true;
    }

}