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

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

There is a newer version: 6.5.21
Show newest version
/*
 * 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 java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;

import org.apache.sling.api.SlingException;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;

import com.adobe.granite.xss.XSSAPI;
import com.day.cq.wcm.foundation.forms.impl.ResourceWrapper;


/**
 * Helper class for the field components.
 * @since 5.3
 */
public class FieldHelper {
    private static final String SLING_SCRIPTING_USER = "sling-scripting";

    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.
     * @throws ServletException if given resource can not be included
     * @throws IOException if given resource can not be included
     */
    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.
     *
     * @param request request
     * @param desc description
     * @return path to the field
     */
    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 description
     * @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);
        XSSAPI xssapi = request.adaptTo(XSSAPI.class);
        return "document.forms[\"" + xssapi.encodeForJSString(formId) + "\"]"
                + ".elements[\"" + xssapi.encodeForJSString(desc.getName() + suffix) + "\"]";
    }

    /**
     * Return the current field description.
     * This method can be used by constraints to get the current
     * field description.
     *
     * @param req request
     * @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.
     *
     * @param request request
     * @param response response
     * @param desc field description
     * @throws IOException if write caused an error
     */
    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);
            String requiredMsg = desc.getRequiredMessage();
            // localize required message
            requiredMsg = FormsHelper.getLocalizedMessage(requiredMsg, request);
            out.write("if (cq5forms_isEmpty(");
            out.write(qualifier);
            out.write(")) {cq5forms_showMsg('");
            XSSAPI xssapi = request.adaptTo(XSSAPI.class);
            out.write(xssapi.encodeForJSString(formId));
            out.write("','");
            out.write(xssapi.encodeForJSString(desc.getName()));
            out.write("','");
            out.write(xssapi.encodeForJSString(requiredMsg));
            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 = getScriptResourceResolver();
            try {
                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++;
                }
            } finally {
                resourceResolver.close();
            }
            if ( msg == null ) {
                msg = "Field is not valid.";
            }
        }
        // localize msg
        msg = FormsHelper.getLocalizedMessage(msg, request);
        return msg;
    }

    /**
     * Write client regexp text.
     *
     * @param request request
     * @param response response
     * @param desc field description
     * @param regexp regexp text
     * @throws IOException if write caused an error
     *
     */
    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(";");
        out.write("if (typeof obj !== 'undefined') { ");
        out.write("if (cq5forms_isArray(obj)) {" +
                  "for(i=0;i 0) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Checks that the required property of a field is set and that the field name exists in the request.
     * @param request request
     * @param desc description
     * @return true if field is required and exists in the request
     */
    private static boolean isRequired(SlingHttpServletRequest request, FieldDescription desc) {

        // CQ5-34399: ignore required fields that were hidden by abacus
        String[] abacus_fields = request.getParameterValues(FormsConstants.REQUEST_PROPERTY_FIELD_HIDDEN);
        if (abacus_fields != null) {
            for (int i = 0; i < abacus_fields.length; i++) {
                if (abacus_fields[i].trim().equals(desc.getName())) {
                    return false;
                }
            }
        }

        return  desc.isRequired();

    }

    /**
     * Get a {@link ResourceResolver} backed by the Sling scripting user so we can read properties from the search path
     * @return resource resolver
     */
    private static ResourceResolver getScriptResourceResolver() {
        BundleContext bundleContext = FrameworkUtil.getBundle(FieldHelper.class).getBundleContext();
        ServiceReference factoryRef = bundleContext.getServiceReference(ResourceResolverFactory.class.getName());
        ResourceResolverFactory resolverFactory = (ResourceResolverFactory) bundleContext.getService(factoryRef);
        final Map authenticationInfo = new HashMap();
        authenticationInfo.put(ResourceResolverFactory.SUBSERVICE, SLING_SCRIPTING_USER);
        try {
            return resolverFactory.getServiceResourceResolver(authenticationInfo);
        } catch (LoginException e) {
            throw new RuntimeException(e);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy