Package org.apache.cocoon.forms.transformation

Source Code of org.apache.cocoon.forms.transformation.WidgetReplacingPipe$InsertStylingContentHandler

/*
* Copyright 1999-2004 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 java.util.Locale;

import org.apache.avalon.excalibur.pool.Recyclable;
import org.apache.cocoon.forms.Constants;
import org.apache.cocoon.forms.formmodel.ContainerWidget;
import org.apache.cocoon.forms.formmodel.Repeater;
import org.apache.cocoon.forms.formmodel.Widget;
import org.apache.cocoon.i18n.I18nUtils;
import org.apache.cocoon.xml.AbstractXMLPipe;
import org.apache.cocoon.xml.SaxBuffer;
import org.apache.cocoon.xml.XMLUtils;
import org.apache.commons.jxpath.JXPathException;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

/**
* The basic operation of this Pipe is that it replaces wt:widget (in the
* {@link Constants#TEMPLATE_NS} namespace) tags (having an id attribute)
* by the XML representation of the corresponding widget instance.
*
* <p>These XML fragments (normally all in the
* {@link Constants#INSTANCE_NS "Cocoon Forms Instance"} namespace), can then be
* translated to a HTML presentation by an XSL. This XSL will then only have to
* style individual widget, and will not need to do the whole page layout.
*
* <p>For more information about the supported tags and their function, see the user documentation
* for the forms template transformer.</p>
*
* @version CVS $Id: WidgetReplacingPipe.java,v 1.8 2004/05/07 16:43:43 mpo Exp $
*/
public class WidgetReplacingPipe extends AbstractXMLPipe {

    private static final String REPEATER_SIZE = "repeater-size";
    private static final String REPEATER_WIDGET_LABEL = "repeater-widget-label";
    private static final String WIDGET_LABEL = "widget-label";
    private static final String WIDGET = "widget";
    private static final String LOCATION = "location";
    private static final String REPEATER_WIDGET = "repeater-widget";
    private static final String CONTINUATION_ID = "continuation-id";
    private static final String FORM_TEMPLATE_EL = "form-template";
    private static final String STYLING_EL = "styling";

    protected Widget contextWidget;

    /**
     * Indicates whether we're currently in a widget element.
     */
    protected boolean inWidgetElement;

    /**
     * Buffer used to temporarily record SAX events.
     */
    protected SaxBuffer saxBuffer;

    /**
     * Counts the element nesting.
     */
    protected int elementNestingCounter;

    /**
     * Contains the value of the {@link #elementNestingCounter} on the moment the transformer
     * encountered a wi:widget element. Used to detect the corresponding endElement call
     * for the wi:widget element.
     */
    protected int widgetElementNesting;

    /**
     * If {@link #inWidgetElement} = true, then this contains the widget currenlty being handled.
     */
    protected Widget widget;

    /**
     * Boolean indicating wether the current widget requires special repeater-treatement.
     */
    protected boolean repeaterWidget;

    protected WidgetReplacingPipe.InsertStylingContentHandler stylingHandler = new WidgetReplacingPipe.InsertStylingContentHandler();
    protected FormsPipelineConfig pipeContext;

    /**
     * Have we encountered a <wi:style> element in a widget ?
     */
    protected boolean gotStylingElement;

    /**
     * Namespace prefix used for the namespace <code>Constants.FT_NS</code>.
     */
    protected String namespacePrefix;
   

    public void init(Widget newContextWidget, FormsPipelineConfig newPipeContext) {
        contextWidget = newContextWidget;
        inWidgetElement = false;
        elementNestingCounter = 0;
        pipeContext = newPipeContext;
    }

    public void startElement(String namespaceURI, String localName, String qName, Attributes attributes)
            throws SAXException {
        elementNestingCounter++;

        if (inWidgetElement) {
            if (elementNestingCounter == widgetElementNesting + 1 &&
                Constants.INSTANCE_NS.equals(namespaceURI) && STYLING_EL.equals(localName)) {
                gotStylingElement = true;
            }
            saxBuffer.startElement(namespaceURI, localName, qName, attributes);
        } else if (Constants.TEMPLATE_NS.equals(namespaceURI)) {
            if (localName.equals(WIDGET) || localName.equals(REPEATER_WIDGET)) {
                checkContextWidgetAvailable(qName);
                inWidgetElement = true;
                widgetElementNesting = elementNestingCounter;
                gotStylingElement = false;
                saxBuffer = new SaxBuffer();
                // retrieve widget here, but its XML will only be streamed in the endElement call
                widget = getWidget(attributes);
                repeaterWidget = localName.equals(REPEATER_WIDGET);
                if (repeaterWidget && !(widget instanceof Repeater)) {
                    throw new SAXException("FormsTemplateTransformer: the element \"repeater-widget\" can only be used for repeater widgets.");
                }
            } else if (localName.equals(WIDGET_LABEL)) {
                checkContextWidgetAvailable(qName);
                Widget widget = getWidget(attributes);
                widget.generateLabel(contentHandler);
            } else if (localName.equals(REPEATER_WIDGET_LABEL)) {
                checkContextWidgetAvailable(qName);
                Widget widget = getWidget(attributes);
                if (!(widget instanceof Repeater)) {
                    throw new SAXException("FormsTemplateTransformer: the element \"repeater-widget-label\" can only be used for repeater widgets.");
                }
                String widgetId = attributes.getValue("widget-id");
                if (widgetId == null || widgetId.equals("")) {
                    throw new SAXException("FormsTemplateTransformer: the element \"repeater-widget-label\" requires a \"widget-id\" attribute.");
                }
                ((Repeater)widget).generateWidgetLabel(widgetId, contentHandler);
            } else if (localName.equals(REPEATER_SIZE)) {
                checkContextWidgetAvailable(qName);
                Widget widget = getWidget(attributes);
                if (!(widget instanceof Repeater))
                    throw new SAXException("FormsTemplateTransformer: the element \"repeater-size\" can only be used for repeater widgets.");
                contentHandler.startPrefixMapping(Constants.INSTANCE_PREFIX, Constants.INSTANCE_NS);
                ((Repeater)widget).generateSize(contentHandler);
                contentHandler.endPrefixMapping(Constants.INSTANCE_PREFIX);
            } else if (localName.equals(FORM_TEMPLATE_EL)) {
                if (contextWidget != null) {
                    throw new SAXException("Detected nested ft:form-template elements, this is not allowed.");
                }
                contentHandler.startPrefixMapping(Constants.INSTANCE_PREFIX, Constants.INSTANCE_NS);

                // ====> Retrieve the form

                // first look for the form using the location attribute, if any
                String formJXPath = attributes.getValue(LOCATION);
                if (formJXPath != null) {
                    // remove the location attribute
                    AttributesImpl attrsCopy = new AttributesImpl(attributes);
                    attrsCopy.removeAttribute(attributes.getIndex(LOCATION));
                    attributes = attrsCopy;
                }
                contextWidget = pipeContext.findForm(formJXPath);

                // ====> Determine the Locale
                //TODO pull this locale stuff also up in the Config object?

                String localeAttr = attributes.getValue("locale");
                if (localeAttr != null) { // first use value of locale attribute if any
                    localeAttr = pipeContext.translateText(localeAttr);
                    pipeContext.setLocale(I18nUtils.parseLocale(localeAttr));
                } else if (pipeContext.getLocaleParameter() != null) { // then use locale specified as transformer parameter, if any
                    pipeContext.setLocale(pipeContext.getLocaleParameter());
                } else { // use locale specified in bizdata supplied for form
                    Object locale = null;
                    try {
                        locale = pipeContext.evaluateExpression("/locale");
                    } catch (JXPathException e) {}
                    if (locale != null) {
                        pipeContext.setLocale((Locale)locale);
                    }
                    else {
                        // final solution: use locale defined in the server machine
                        pipeContext.setLocale(Locale.getDefault());
                    }
                }

                String[] namesToTranslate = {"action"};
                Attributes transAtts = translateAttributes(attributes, namesToTranslate);
                contentHandler.startElement(Constants.INSTANCE_NS , FORM_TEMPLATE_EL, Constants.INSTANCE_PREFIX_COLON + FORM_TEMPLATE_EL, transAtts);

            } else if (localName.equals(CONTINUATION_ID)){
                // Insert the continuation id
                // FIXME(SW) we could avoid costly JXPath evaluation if we had the objectmodel here.
                Object idObj = pipeContext.evaluateExpression("$continuation/id");
                if (idObj == null) {
                    throw new SAXException("No continuation found");
                }

                String id = idObj.toString();
                contentHandler.startPrefixMapping(Constants.INSTANCE_PREFIX, Constants.INSTANCE_NS);
                contentHandler.startElement(Constants.INSTANCE_NS, CONTINUATION_ID, Constants.INSTANCE_PREFIX_COLON + CONTINUATION_ID, attributes);
                contentHandler.characters(id.toCharArray(), 0, id.length());
                contentHandler.endElement(Constants.INSTANCE_NS, CONTINUATION_ID, Constants.INSTANCE_PREFIX_COLON + CONTINUATION_ID);
                contentHandler.endPrefixMapping(Constants.INSTANCE_PREFIX);
            } else {
                throw new SAXException("FormsTemplateTransformer: Unsupported element: " + localName);
            }
        } else {
            super.startElement(namespaceURI, localName, qName, attributes);
        }
    }

    private void checkContextWidgetAvailable(String widgetElementName) throws SAXException {
        if (contextWidget == null)
            throw new SAXException(widgetElementName + " cannot be used outside a wt:form-template element");
    }

    private Attributes translateAttributes(Attributes attributes, String[] names) {
        AttributesImpl newAtts = new AttributesImpl(attributes);
        if (names!= null) {
            for (int i = 0; i < names.length; i++) {
                String name = names[i];
                int position = newAtts.getIndex(name);
                String newValue = pipeContext.translateText(newAtts.getValue(position));
                newAtts.setValue(position, newValue);               
            }
        }
        return newAtts;
    }


    protected Widget getWidget(Attributes attributes) throws SAXException {
        String widgetId = attributes.getValue("id");
        if (widgetId == null || widgetId.equals("")) {
            throw new SAXException("FormsTemplateTransformer: missing id attribute on a Cocoon Forms element.");
        }
        Widget widget = ((ContainerWidget)contextWidget).getChild(widgetId);
        if (widget == null) {
            throw new SAXException("FormsTemplateTransformer: widget with id \"" + widgetId + "\" does not exist in the container " + contextWidget.getRequestParameterName());
        }
        return widget;
    }

    public void endElement(String namespaceURI, String localName, String qName)
            throws SAXException {

        if (inWidgetElement) {
            if (elementNestingCounter == widgetElementNesting && Constants.TEMPLATE_NS.equals(namespaceURI)
                && (localName.equals(WIDGET) || localName.equals(REPEATER_WIDGET))) {
                    if (repeaterWidget) {
                        Repeater repeater = (Repeater)widget;
                        WidgetReplacingPipe rowPipe = new WidgetReplacingPipe();
                        int rowCount = repeater.getSize();
                        for (int i = 0; i < rowCount; i++) {
                            Repeater.RepeaterRow row = repeater.getRow(i);
                            rowPipe.init(row, pipeContext);
                            rowPipe.setContentHandler(contentHandler);
                            rowPipe.setLexicalHandler(lexicalHandler);
                            saxBuffer.toSAX(rowPipe);
                            rowPipe.recycle();
                        }
                    } else {
                        stylingHandler.recycle();
                        stylingHandler.setSaxFragment(saxBuffer);
                        stylingHandler.setContentHandler(contentHandler);
                        stylingHandler.setLexicalHandler(lexicalHandler);
                        contentHandler.startPrefixMapping(Constants.INSTANCE_PREFIX, Constants.INSTANCE_NS);
                        widget.generateSaxFragment(stylingHandler, pipeContext.getLocale());
                        contentHandler.endPrefixMapping(Constants.INSTANCE_PREFIX);
                    }
                    inWidgetElement = false;
                    widget = null;
                } else {
                    saxBuffer.endElement(namespaceURI, localName, qName);
                }
        } else if (Constants.TEMPLATE_NS.equals(namespaceURI)) {
            if (localName.equals(WIDGET_LABEL) || localName.equals(REPEATER_WIDGET_LABEL)
                || localName.equals(REPEATER_SIZE) || localName.equals(CONTINUATION_ID)) {
                // Do nothing
            } else if (localName.equals(FORM_TEMPLATE_EL)) {
                contextWidget = null;
                contentHandler.endElement(Constants.INSTANCE_NS, FORM_TEMPLATE_EL,
                                          Constants.INSTANCE_PREFIX_COLON + FORM_TEMPLATE_EL);
                contentHandler.endPrefixMapping(Constants.INSTANCE_PREFIX);
            } else {
                super.endElement(namespaceURI, localName, qName);
            }
        } else {
            super.endElement(namespaceURI, localName, qName);
        }
        elementNestingCounter--;
    }

    public void startPrefixMapping(String prefix, String uri)
            throws SAXException {
        if (inWidgetElement) {
            saxBuffer.startPrefixMapping(prefix, uri);
        } else {
            super.startPrefixMapping(prefix, uri);
        }
    }

    public void endPrefixMapping(String prefix)
            throws SAXException {
        if (inWidgetElement) {
            saxBuffer.endPrefixMapping(prefix);
        } else {
            super.endPrefixMapping(prefix);
        }
    }

    public void characters(char c[], int start, int len)
            throws SAXException {
        if (inWidgetElement) {
            saxBuffer.characters(c, start, len);
        } else {
            super.characters(c, start, len);
        }
    }

    public void ignorableWhitespace(char c[], int start, int len)
            throws SAXException {
        if (inWidgetElement) {
            saxBuffer.ignorableWhitespace(c, start, len);
        } else {
            super.ignorableWhitespace(c, start, len);
        }
    }

    public void processingInstruction(String target, String data)
            throws SAXException {
        if (inWidgetElement) {
            saxBuffer.processingInstruction(target, data);
        } else {
            super.processingInstruction(target, data);
        }
    }

    public void skippedEntity(String name)
            throws SAXException {
        if (inWidgetElement) {
            saxBuffer.skippedEntity(name);
        } else {
            super.skippedEntity(name);
        }
    }

    public void startEntity(String name)
            throws SAXException {
        if (inWidgetElement)
            saxBuffer.startEntity(name);
        else
            super.startEntity(name);
    }

    public void endEntity(String name)
            throws SAXException {
        if (inWidgetElement) {
            saxBuffer.endEntity(name);
        } else {
            super.endEntity(name);
        }
    }

    public void startCDATA()
            throws SAXException {
        if (inWidgetElement) {
            saxBuffer.startCDATA();
        } else {
            super.startCDATA();
        }
    }

    public void endCDATA()
            throws SAXException {
        if (inWidgetElement) {
            saxBuffer.endCDATA();
        } else {
            super.endCDATA();
        }
    }

    public void comment(char ch[], int start, int len)
            throws SAXException {
        if (inWidgetElement) {
            saxBuffer.comment(ch, start, len);
        } else {
            super.comment(ch, start, len);
        }
    }

    public void recycle() {
        super.recycle();
        this.contextWidget = null;
        this.widget = null;
        this.namespacePrefix = null;
    }

    /**
     * This ContentHandler helps in inserting SAX events before the closing tag of the root
     * element.
     */
    public class InsertStylingContentHandler extends AbstractXMLPipe implements Recyclable {
        private int elementNesting;
        private SaxBuffer saxBuffer;

        public void setSaxFragment(SaxBuffer saxFragment) {
            saxBuffer = saxFragment;
        }

        public void recycle() {
            super.recycle();
            elementNesting = 0;
            saxBuffer = null;
        }

        public void startElement(String uri, String loc, String raw, Attributes a)
                throws SAXException {
            elementNesting++;
            super.startElement(uri, loc, raw, a);
        }

        public void endElement(String uri, String loc, String raw)
                throws SAXException {
            elementNesting--;
            if (elementNesting == 0 && saxBuffer != null) {
                if (gotStylingElement) {
                    // Just deserialize
                    saxBuffer.toSAX(contentHandler);
                } else {
                    // Insert an enclosing <wi:styling>
                    contentHandler.startElement(Constants.INSTANCE_NS, STYLING_EL, Constants.INSTANCE_PREFIX_COLON + STYLING_EL, XMLUtils.EMPTY_ATTRIBUTES);
                    saxBuffer.toSAX(contentHandler);
                    contentHandler.endElement(Constants.INSTANCE_NS, STYLING_EL, Constants.INSTANCE_PREFIX_COLON + STYLING_EL);
                }
            }
            super.endElement(uri, loc, raw);
        }
    }
}
TOP

Related Classes of org.apache.cocoon.forms.transformation.WidgetReplacingPipe$InsertStylingContentHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.