org.apache.cocoon.forms.transformation.FormsPipelineConfig.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.cocoon.forms.transformation.FormsPipelineConfig.java

Source

/*
 * Copyright 1999-2005 The Apache Software Foundation.
 *
 * 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.
 */
package org.apache.cocoon.forms.transformation;

import org.apache.avalon.framework.parameters.Parameters;

import org.apache.cocoon.components.flow.FlowHelper;
import org.apache.cocoon.components.flow.WebContinuation;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Session;
import org.apache.cocoon.forms.formmodel.Form;
import org.apache.cocoon.i18n.I18nUtils;
import org.apache.cocoon.util.Deprecation;

import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.JXPathException;
import org.apache.commons.jxpath.Variables;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * @version $Id: FormsPipelineConfig.java 289538 2005-09-16 13:46:22Z sylvain $
 */
public class FormsPipelineConfig {

    /**
     * Default key under which the Cocoon Forms form instance is stored in the JXPath context.
     */
    public static final String CFORMSKEY = "CocoonFormsInstance";

    /**
     * Name of the request attribute under which the Cocoon Form is stored (optional). */
    private final String attributeName;

    /**
     * Pointer to the current request object.
     */
    private final Request request;

    /**
     * Initialized jxpathcontext to evaluate passed expressions with.
     */
    private final JXPathContext jxpathContext;

    /**
     * Containts locale specified as a parameter to the transformer, if any.
     */
    private final Locale localeParameter;

    /**
     * The locale currently used by the transformer.
     */
    private Locale locale;

    /**
     * Value for the action attribute of the form.
     */
    private String formAction;

    /**
     * Value for the method attribute of the form.
     */
    private String formMethod;

    private FormsPipelineConfig(JXPathContext jxpc, Request req, Locale localeParam, String attName,
            String actionExpression, String method) {
        this.attributeName = attName;
        this.request = req;
        this.jxpathContext = jxpc;
        this.localeParameter = localeParam;
        this.formAction = translateText(actionExpression);
        this.formMethod = method;
    }

    /**
     * Creates and initializes a FormsPipelineConfig object based on the passed
     * arguments of the setup() of the specific Pipeline-component.
     *
     * @param objectModel the objectmodel as passed in the setup()
     * @param parameters the parameters as passed in the setup()
     * @return an instance of FormsPipelineConfig initialized according to the
     * settings in the sitemap.
     */
    public static FormsPipelineConfig createConfig(Map objectModel, Parameters parameters) {
        // create and set the jxpathContext...
        Object flowContext = FlowHelper.getContextObject(objectModel);
        WebContinuation wk = FlowHelper.getWebContinuation(objectModel);
        JXPathContext jxpc = JXPathContext.newContext(flowContext);
        // We manually create a cocoon object here to provide the same way
        // of accessing things as in the jxtg
        // as soon as we have our unified om, we should use that
        Request request = ObjectModelHelper.getRequest(objectModel);
        Session session = request.getSession(false);
        final Map cocoonOM = new HashMap();
        cocoonOM.put("continuation", wk);
        cocoonOM.put("request", request);
        if (session != null) {
            cocoonOM.put("session", session);
        }
        cocoonOM.put("parameters", parameters);

        FormsVariables vars = new FormsVariables();
        vars.declareVariable("cocoon", cocoonOM);
        // These four are deprecated!
        vars.declareVariable("continuation", wk);
        vars.declareVariable("request", request);
        vars.declareVariable("session", session);
        vars.declareVariable("parameters", parameters);
        vars.addDeprecatedVariable("continuation");
        vars.addDeprecatedVariable("request");
        vars.addDeprecatedVariable("session");
        vars.addDeprecatedVariable("parameters");
        jxpc.setVariables(vars);

        Locale localeParameter = null;
        String localeStr = parameters.getParameter("locale", null);
        if (localeStr != null) {
            localeParameter = I18nUtils.parseLocale(localeStr);
        }

        String attributeName = parameters.getParameter("attribute-name", null);
        String actionExpression = parameters.getParameter("form-action", null);
        String formMethod = parameters.getParameter("form-method", null);
        //TODO (20031223 mpo)think about adding form-encoding for the Generator.
        // Note generator will also need some text to go on the submit-button?
        // Alternative to adding more here is to apply xinclude ?

        return new FormsPipelineConfig(jxpc, request, localeParameter, attributeName, actionExpression, formMethod);
    }

    /**
     * Overloads {@link #findForm(String)} by setting the jxpath-expression to null
     */
    public Form findForm() throws SAXException {
        return this.findForm(null);
    }

    /**
     * Finds the form from the current request-context based on the settings of
     * this configuration object.  The fall-back search-procedure is as follows:
     * <ol><li>Use the provided jxpathExpression (if not null)</li>
     * <li>Use the setting of the 'attribute-name' parameter on the request</li>
     * <li>Obtain the form from it's default location in the flow context</li>
     * </ol>
     *
     * @param jxpathExpression that should be pointing to the form
     * @return the found form if found
     * @throws SAXException in any of the following cases:
     * <ul><li>The provided jxpathExpression (if not null) not point to a
     * {@link Form} instance.</li>
     * <li>The request is not holding a {@link Form} instance under the key
     * specified by 'attribute-name' (if specified)</li>
     * <li>Both jxpathExpression and 'attribute-name' were not specified AND
     * also the default location was not holding a valid {@link Form} instance.</li>
     * </ol>
     */
    public Form findForm(String jxpathExpression) throws SAXException {
        Object form = null;
        if (jxpathExpression != null) {
            form = this.jxpathContext.getValue(jxpathExpression);
            if (form == null) {
                throw new SAXException("No Cocoon Form found at location \"" + jxpathExpression + "\".");
            } else if (!(form instanceof Form)) {
                throw new SAXException(
                        "Object returned by expression \"" + jxpathExpression + "\" is not a Cocoon Form.");
            }
        } else if (this.attributeName != null) { // then see if an attribute-name was specified
            form = this.request.getAttribute(this.attributeName);
            if (form == null) {
                throw new SAXException(
                        "No Cocoon Form found in request attribute with name \"" + this.attributeName + "\"");
            } else if (!(form instanceof Form)) {
                throw new SAXException(
                        "Object found in request (attribute = '" + this.attributeName + "') is not a Cocoon Form.");
            }
        } else { // and then see if we got a form from the flow
            jxpathExpression = "/" + FormsPipelineConfig.CFORMSKEY;
            try {
                form = this.jxpathContext.getValue(jxpathExpression);
            } catch (JXPathException e) {
                /* do nothing */ }
            if (form == null) {
                throw new SAXException("No Cocoon Form found.");
            }
        }
        return (Form) form;
    }

    /**
     * Replaces JXPath expressions embedded inside #{ and } by their value.
     * This will parse the passed String looking for #{} occurences and then
     * uses the {@link #evaluateExpression(String)} to evaluate the found expression.
     *
     * @return the original String with it's #{}-parts replaced by the evaulated results.
     */
    public String translateText(String original) {
        if (original == null) {
            return null;
        }

        StringBuffer expression;
        StringBuffer translated = new StringBuffer();
        StringReader in = new StringReader(original);
        int chr;
        try {
            while ((chr = in.read()) != -1) {
                char c = (char) chr;
                if (c == '#') {
                    chr = in.read();
                    if (chr != -1) {
                        c = (char) chr;
                        if (c == '{') {
                            expression = new StringBuffer();
                            boolean more = true;
                            while (more) {
                                more = false;
                                if ((chr = in.read()) != -1) {
                                    c = (char) chr;
                                    if (c != '}') {
                                        expression.append(c);
                                        more = true;
                                    } else {
                                        translated.append(evaluateExpression(expression.toString()).toString());
                                    }
                                } else {
                                    translated.append('#').append('{').append(expression);
                                }
                            }
                        }
                    } else {
                        translated.append((char) chr);
                    }
                } else {
                    translated.append(c);
                }
            }
        } catch (IOException ignored) {
            ignored.printStackTrace();
        }
        return translated.toString();
    }

    /**
     * Evaluates the passed xpath expression using the internal jxpath context
     * holding the declared variables:
     * <ol><li>continuation: as made available by flowscript</li>
     * <li>request: as present in the cocoon processing environment</li>
     * <li>session: as present in the cocoon processing environment</li>
     * <li>parameters: as present in the cocoon sitemap node of the pipeline component</li></ol>
     *
     * @param expression
     * @return the object-value resulting the expression evaluation.
     */
    public Object evaluateExpression(String expression) {
        return this.jxpathContext.getValue(expression);
    }

    public Locale getLocale() {
        return locale;
    }

    public void setLocale(Locale locale) {
        this.locale = locale;
    }

    public Locale getLocaleParameter() {
        return localeParameter;
    }

    /**
     * The value for the wi:form-generated/@action.
     * Note: wi:form-template copies this from its wt:form-template counterpart.
     *
     * @return the {@link #translateText(String)} result of the 'form-action' sitemap
     * parameter to the pipeline component, or null if that parameter was not set.
     */
    public String getFormAction() {
        return formAction;
    }

    /**
     * The value for the wi:form-generated/@method.
     * Note: wi:form-template copies this from its wt:form-template counterpart.
     *
     * @return the value of the 'form-method' sitemap parameter to the pipeline
     * component. (or 'null' if it was not set.)
     */
    public String getFormMethod() {
        return formMethod;
    }

    /**
     * Sets the form method to use in the generator/transformer that uses this.
     *
     * @param method to use in the generated form should be "POST", "GET" or null
     */
    public void setFormMethod(String method) {
        this.formMethod = method;
    }

    /**
     * The grouped attributes to set on the wi:form-generated element.
     * Note: wi:form-template copies this from its wt:form-template counterpart.
     *
     * @see #getFormAction()
     * @see #getFormMethod()
     */
    public Attributes getFormAttributes() {
        AttributesImpl attrs = new org.apache.cocoon.xml.AttributesImpl();
        addFormAttributes(attrs);
        return attrs;
    }

    public void addFormAttributes(AttributesImpl attrs) {
        if (getFormAction() != null) {
            attrs.addAttribute("", "action", "action", "CDATA", getFormAction());
        }
        if (getFormMethod() != null) {
            attrs.addAttribute("", "method", "method", "CDATA", getFormMethod());
        }
    }

    public static final class FormsVariables implements Variables {

        final Map vars = new HashMap();
        final List deprecatedNames = new ArrayList();

        public void addDeprecatedVariable(String name) {
            this.deprecatedNames.add(name);
        }

        /* (non-Javadoc)
         * @see org.apache.commons.jxpath.Variables#declareVariable(java.lang.String, java.lang.Object)
         */
        public void declareVariable(String name, Object value) {
            this.vars.put(name, value);
        }

        /* (non-Javadoc)
         * @see org.apache.commons.jxpath.Variables#getVariable(java.lang.String)
         */
        public Object getVariable(String name) {
            Object value = this.vars.get(name);
            if (deprecatedNames.contains(name)) {
                Deprecation.logger.warn(
                        "CForms: usage of the variable '" + name + "' is deprecated." + "Please use 'cocoon/" + name
                                + "' instead. The usage of just '" + name + "' will be removed in Cocoon 2.2.");
            }
            return value;
        }

        /* (non-Javadoc)
         * @see org.apache.commons.jxpath.Variables#isDeclaredVariable(java.lang.String)
         */
        public boolean isDeclaredVariable(String name) {
            return this.vars.containsKey(name);
        }

        /* (non-Javadoc)
         * @see org.apache.commons.jxpath.Variables#undeclareVariable(java.lang.String)
         */
        public void undeclareVariable(String name) {
            this.vars.remove(name);
        }
    }
}