cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jheym...@apache.org
Subject svn commit: r330548 [101/132] - in /cocoon/whiteboard/maven2/cocoon-flat-layout: ./ cocoon-ajax-block/ cocoon-ajax-block/api/ cocoon-ajax-block/api/src/ cocoon-ajax-block/api/src/main/ cocoon-ajax-block/api/src/main/java/ cocoon-ajax-block/api/src/main...
Date Thu, 03 Nov 2005 14:00:48 GMT
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/generation/JXMacrosHelper.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/generation/JXMacrosHelper.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/generation/JXMacrosHelper.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/generation/JXMacrosHelper.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,486 @@
+/*
+ * 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.generation;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cocoon.ajax.BrowserUpdateTransformer;
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.forms.FormsConstants;
+import org.apache.cocoon.forms.FormsRuntimeException;
+import org.apache.cocoon.forms.formmodel.Form;
+import org.apache.cocoon.forms.formmodel.Repeater;
+import org.apache.cocoon.forms.formmodel.Widget;
+import org.apache.cocoon.forms.formmodel.tree.Tree;
+import org.apache.cocoon.forms.formmodel.tree.TreeWalker;
+import org.apache.cocoon.forms.validation.ValidationError;
+import org.apache.cocoon.i18n.I18nUtils;
+import org.apache.cocoon.xml.AbstractXMLPipe;
+import org.apache.cocoon.xml.AttributesImpl;
+import org.apache.cocoon.xml.XMLConsumer;
+import org.apache.cocoon.xml.XMLUtils;
+import org.apache.commons.collections.ArrayStack;
+import org.apache.commons.lang.BooleanUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+/**
+ * Helper class for the implementation of the CForms template language with JXTemplate macros.
+ *
+ * @version $Id$
+ */
+public class JXMacrosHelper {
+
+    private XMLConsumer cocoonConsumer;
+    private Request request;
+    private Locale locale;
+    private ArrayStack widgetStack = new ArrayStack();
+    private ArrayStack pipeStack = new ArrayStack();
+    private Map classes; // lazily created
+    private boolean ajaxRequest;
+    private boolean ajaxTemplate;
+    private Set updatedWidgets;
+    private Set childUpdatedWidgets;
+
+    /**
+     * Builds and helper object, given the generator's consumer.
+     *
+     * @param consumer the generator's consumer
+     * @return a helper object
+     */
+    public static JXMacrosHelper createHelper(XMLConsumer consumer, Request request, String locale) {
+        return new JXMacrosHelper(consumer, request, locale);
+    }
+
+    public JXMacrosHelper(XMLConsumer consumer, Request request, String locale) {
+        this.cocoonConsumer = consumer;
+        this.request = request;
+        this.locale = I18nUtils.parseLocale(locale);
+        this.ajaxRequest = request.getParameter("cocoon-ajax") != null;
+    }
+
+    public Form getForm(Form form, String attributeName) {
+        Form returnForm = form;
+        // if there hasn't been passed a form object, try to find it in the request
+        if(returnForm == null) {
+            returnForm = (Form) this.request.getAttribute(attributeName);
+        }
+        if(returnForm != null) {
+            return returnForm;
+        }
+        throw new FormsRuntimeException("The template cannot find a form object");
+    }
+
+    public void startForm(Form form, Map attributes) throws SAXException {
+        
+        this.updatedWidgets = form.getUpdatedWidgetIds();
+        this.childUpdatedWidgets = form.getChildUpdatedWidgetIds();
+        
+        // build attributes
+        AttributesImpl attrs = new AttributesImpl();
+        Iterator iter = attributes.entrySet().iterator();
+        while(iter.hasNext()) {
+            Map.Entry entry = (Map.Entry)iter.next();
+            attrs.addCDATAAttribute((String)entry.getKey(), (String)entry.getValue());
+        }
+        
+        this.ajaxTemplate = "true".equals(attributes.get("ajax"));
+
+        this.cocoonConsumer.startPrefixMapping(FormsConstants.INSTANCE_PREFIX, FormsConstants.INSTANCE_NS);
+        this.cocoonConsumer.startElement(FormsConstants.INSTANCE_NS,
+                                         "form-template",
+                                         FormsConstants.INSTANCE_PREFIX_COLON + "form-template",
+                                         attrs);
+        // Push the form at the top of the stack
+        this.widgetStack.push(Boolean.FALSE); // Not in an updated template
+        this.widgetStack.push(form);
+    }
+
+    public void endForm() throws SAXException {
+        this.widgetStack.pop();
+        this.widgetStack.pop();
+        this.cocoonConsumer.endElement(FormsConstants.INSTANCE_NS,
+                                       "form-template",
+                                       FormsConstants.INSTANCE_PREFIX_COLON + "form-template");
+        this.cocoonConsumer.endPrefixMapping(FormsConstants.INSTANCE_PREFIX);
+        
+        this.ajaxTemplate = false;
+        this.updatedWidgets = null;
+    }
+    
+    private void startBuReplace(String id) throws SAXException {
+        AttributesImpl attr = new AttributesImpl();
+        attr.addCDATAAttribute("id", id);
+        this.cocoonConsumer.startElement(BrowserUpdateTransformer.BU_NSURI, "replace", "bu:replace", attr);
+    }
+    
+    private void endBuReplace(String id) throws SAXException {
+        this.cocoonConsumer.endElement(BrowserUpdateTransformer.BU_NSURI, "replace", "bu:replace");
+    }
+    
+    protected boolean pushWidget(String path, boolean unused) throws SAXException {
+        Widget parent = peekWidget();
+        if (path == null || path.length() == 0) {
+            throw new FormsRuntimeException("Missing 'id' attribute on template instruction");
+        }
+        Widget widget = parent.lookupWidget(path);
+        if (widget == null) {
+            throw new FormsRuntimeException(parent + " has no child named '" + path + "'", parent.getLocation());
+        }
+
+        String id = widget.getFullName();
+        // Is there an updated widget at a higher level in the template?
+        boolean inUpdatedTemplate = ((Boolean)widgetStack.peek(1)).booleanValue();
+
+        boolean display;
+
+        if (ajaxRequest) {
+            // An Ajax request. We will send partial updates
+            if (inUpdatedTemplate) {
+                // A parent widget has been updated: redisplay this one also
+                display = true;
+            } else if (this.updatedWidgets.contains(id)) {
+                // Widget has been updated. We are now in an updated template section,
+                // and widgets have to be surrounded with <bu:replace>
+                inUpdatedTemplate = true;
+                display = true;
+            } else if (this.childUpdatedWidgets.contains(id)) {
+                // A child need to be updated
+                display = true;
+            } else {
+                // Doesn't need to be displayed
+                display = false;
+            }
+        } else {
+            // Not an ajax request
+            if (ajaxTemplate) {
+                // Surround all widgets with <bu:replace>, which the bu tranformer will use to check structure
+                // consistency and add an id attribute to its child elements.
+                inUpdatedTemplate = true;
+            }
+            // Display the widget
+            display = true;
+        }
+        
+        if (display) {
+            // Widget needs to be displayed, but does it actually allows it?
+            if (widget.getState().isDisplayingValues()) {
+                if (inUpdatedTemplate) {
+                    // Updated part of an Ajax template: surround with <bu:replace>
+                    startBuReplace(id);
+                }
+            } else {
+                if (ajaxTemplate) {
+                    // Generate a placeholder, so that the page can be updated later
+                    startBuReplace(id);
+                    AttributesImpl attrs = new AttributesImpl();
+                    attrs.addCDATAAttribute("id", id);
+                    this.cocoonConsumer.startElement(FormsConstants.INSTANCE_NS, "placeholder", FormsConstants.INSTANCE_PREFIX_COLON + "placeholder", attrs);
+                    this.cocoonConsumer.endElement(FormsConstants.INSTANCE_NS, "placeholder", FormsConstants.INSTANCE_PREFIX_COLON + "placeholder");
+                    endBuReplace(id);
+                }
+                // Production finished for this widget
+                display = false;
+            }
+        }
+
+        if (display) {
+            this.widgetStack.push(BooleanUtils.toBooleanObject(inUpdatedTemplate));
+            this.widgetStack.push(widget);
+        }
+        
+        return display;
+    }
+    
+    public Widget peekWidget() {
+        return (Widget)this.widgetStack.peek();
+    }
+    
+    public void popWidget() throws SAXException {
+        Widget widget = (Widget)this.widgetStack.pop();
+        boolean inUpdatedTemplate = ((Boolean)this.widgetStack.pop()).booleanValue();
+        
+        if (inUpdatedTemplate) {
+            // Close the bu:replace
+            endBuReplace(widget.getFullName());
+        }
+    }
+    
+    public boolean pushWidget(String path) throws SAXException {
+        return pushWidget(path, false);
+    }
+    
+    public boolean pushContainer(String path) throws SAXException {
+        return pushWidget(path, true);
+    }
+
+    /**
+     * Enter a repeater
+     * 
+     * @param path widget path
+     * @param ajaxAware distinguishes between &lt;ft:repeater-widget&gt; and &lt;ft:repeater&gt;.
+     * @return true if the repeater template is to be executed
+     * @throws SAXException
+     */
+    public boolean pushRepeater(String path, boolean ajaxAware) throws SAXException {
+        if (!ajaxAware && this.ajaxTemplate) {
+            throw new IllegalStateException("Cannot use <ft:repeater-widget> in an Ajax form");
+        }
+        boolean result = pushWidget(path, true);
+        if (result && !(peekWidget() instanceof Repeater)) {
+            throw new IllegalArgumentException("Widget " + peekWidget() + " is not a repeater");
+        }
+        return result;
+    }
+    
+    /**
+     * Get a child widget of a given widget, throwing an exception if no such child exists.
+     *
+     * @param currentWidget
+     * @param id
+     */
+    public Widget getWidget(Widget currentWidget, String path) {
+        Widget result = currentWidget.lookupWidget(path);
+
+        if (result != null) {
+            return result;
+        }
+        throw new FormsRuntimeException(currentWidget + " has no child named '" + path + "'", currentWidget.getLocation());
+    }
+
+    private Repeater getRepeater(Widget currentWidget, String id) {
+        Widget child = getWidget(currentWidget, id);
+        if (child instanceof Repeater) {
+            return (Repeater)child;
+        }
+        throw new FormsRuntimeException(child + " is not a repeater", child.getLocation());
+    }
+
+    /**
+     * Generate a widget's SAX fragment, buffering the root element's <code>endElement()</code>
+     * event so that the template can insert styling information in it.
+     *
+     * @param widget
+     * @param locale
+     * @throws SAXException
+     */
+    public void generateWidget(Widget widget, Map arguments) throws SAXException {
+        // Needs to be buffered
+        RootBufferingPipe pipe = new RootBufferingPipe(this.cocoonConsumer, arguments);
+        this.pipeStack.push(pipe);
+        widget.generateSaxFragment(pipe, this.locale);
+    }
+
+    /**
+     * Flush the root element name that has been stored in
+     * {@link #generateWidget(Widget, Locale)}.
+     *
+     * @param obj the object that is terminated (widget or validation error)
+     * @throws SAXException
+     */
+    public void flushRootAndPop() throws SAXException {
+        ((RootBufferingPipe) pipeStack.pop()).flushRoot();
+        popWidget();
+    }
+
+    public void flushRoot() throws SAXException {
+        ((RootBufferingPipe) pipeStack.pop()).flushRoot();
+    }
+
+    public void generateWidgetLabel(Widget widget, String id) throws SAXException {
+        getWidget(widget, id).generateLabel(this.cocoonConsumer);
+    }
+
+    public void generateRepeaterWidgetLabel(Widget widget, String id, String widgetId) throws SAXException {
+        // Widget labels are allowed either inside or outside of <ft:repeater>
+        Repeater repeater = widget instanceof Repeater ? (Repeater)widget : getRepeater(widget, id);
+        repeater.generateWidgetLabel(widgetId, this.cocoonConsumer);
+    }
+
+    public void generateRepeaterSize(Widget widget, String id) throws SAXException {
+        getRepeater(widget, id).generateSize(this.cocoonConsumer);
+    }
+
+    private static final String VALIDATION_ERROR = "validation-error";
+
+    public void generateValidationError(ValidationError error) throws SAXException {
+        // Needs to be buffered
+        RootBufferingPipe pipe = new RootBufferingPipe(this.cocoonConsumer);
+        this.pipeStack.push(pipe);
+        pipe.startElement(FormsConstants.INSTANCE_NS, VALIDATION_ERROR, FormsConstants.INSTANCE_PREFIX_COLON + VALIDATION_ERROR, XMLUtils.EMPTY_ATTRIBUTES);
+        error.generateSaxFragment(pipe);
+        pipe.endElement(FormsConstants.INSTANCE_NS, VALIDATION_ERROR, FormsConstants.INSTANCE_PREFIX_COLON + VALIDATION_ERROR);
+    }
+
+    public boolean isValidationError(Object object) {
+        return object instanceof ValidationError;
+    }
+
+    public void defineClassBody(Form form, String id, Object body) {
+        // TODO: check that class actually exists in the form
+        if (this.classes == null) {
+            this.classes = new HashMap();
+        }
+
+        // TODO: check if class doesn't already exist?
+        this.classes.put(id, body);
+    }
+
+    public Object getClassBody(String id) {
+        Object result = this.classes == null ? null : this.classes.get(id);
+
+        if (result == null) {
+            throw new FormsRuntimeException("No class '" + id + "' has been defined.");
+        } 
+        return result;
+    }
+
+    public boolean isSelectedCase(Widget unionWidget, String caseValue) {
+        String value = (String)unionWidget.getValue();
+        return caseValue.equals(value != null ? value : "");
+    }
+
+    public TreeWalker createWalker() {
+        return new TreeWalker((Tree)peekWidget());
+    }
+    
+    public boolean isVisible(Widget widget) throws SAXException {
+        boolean visible = widget.getCombinedState().isDisplayingValues();
+        
+        if (!visible) {
+            // Generate a placeholder it not visible
+            String id = widget.getRequestParameterName();
+            AttributesImpl attrs = new AttributesImpl();
+            attrs.addCDATAAttribute("id", id);
+            this.cocoonConsumer.startElement(BrowserUpdateTransformer.BU_NSURI, "replace", "bu:replace", attrs);
+            this.cocoonConsumer.startElement(FormsConstants.INSTANCE_NS, "placeholder", FormsConstants.INSTANCE_PREFIX_COLON + "placeholder", attrs);
+            this.cocoonConsumer.endElement(FormsConstants.INSTANCE_NS, "placeholder", FormsConstants.INSTANCE_PREFIX_COLON + "placeholder");
+            this.cocoonConsumer.endElement(BrowserUpdateTransformer.BU_NSURI, "replace", "bu:replace");
+        }
+
+        return visible;
+    }
+    
+    public boolean isModified(Widget widget) {
+        return this.updatedWidgets.contains(widget.getRequestParameterName());
+    }
+    
+    public boolean generateStyling(Map attributes) throws SAXException {
+        return generateStyling(this.cocoonConsumer, attributes);
+    }
+
+    /**
+     * Generate a <code>&lt;fi:styling&gt;</code> element holding the attributes of a <code>ft:*</code>
+     * element that are in the "fi:" namespace.
+     * 
+     * @param attributes the template instruction attributes
+     * @return true if a <code>&lt;fi:styling&gt;</code> was produced
+     * @throws SAXException
+     */
+    public static boolean generateStyling(ContentHandler handler, Map attributes) throws SAXException {
+        AttributesImpl attr = null;
+        Iterator entries = attributes.entrySet().iterator();
+        while(entries.hasNext()) {
+            Map.Entry entry = (Map.Entry)entries.next();
+            String key = (String)entry.getKey();
+            
+            // FIXME: JXTG only gives the local name of attributes, so we can't distinguish namespaces...            
+            if (!"id".equals(key) && !"widget-id".equals(key)) {
+                if (attr == null)
+                    attr = new AttributesImpl();
+                attr.addCDATAAttribute(key, (String)entry.getValue());
+            }
+        }
+        
+        if (attr != null) {
+            // There were some styling attributes
+            handler.startElement(FormsConstants.INSTANCE_NS, "styling", FormsConstants.INSTANCE_PREFIX_COLON + "styling", attr);
+            handler.endElement(FormsConstants.INSTANCE_NS, "styling", FormsConstants.INSTANCE_PREFIX_COLON + "styling");
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * A SAX pipe that buffers the <code>endElement()</code> event of the root element.
+     * This is needed by the generator version of the FormsTransformer (see jx-macros.xml).
+     *
+     * @version $Id$
+     */
+    private static class RootBufferingPipe extends AbstractXMLPipe {
+        private int depth = 0;
+
+        private String rootUri;
+        private String rootLoc;
+        private String rootRaw;
+        private Map arguments;
+        private boolean forbidStyling = false;
+
+        public RootBufferingPipe(XMLConsumer next) {
+            this(next, Collections.EMPTY_MAP);
+        }
+
+        public RootBufferingPipe(XMLConsumer next, Map arguments) {
+            this.setConsumer(next);
+            this.arguments = arguments;
+        }
+
+        public void startElement(String uri, String loc, String raw, Attributes a)
+        throws SAXException {
+            super.startElement(uri, loc, raw, a);
+            if (depth == 0) {
+                // Root element: keep its description
+                this.rootUri = uri;
+                this.rootLoc = loc;
+                this.rootRaw = raw;
+                
+                // And produce fi:styling from attributes
+                this.forbidStyling = generateStyling(this.contentHandler, arguments);
+            }
+            
+            if (depth == 1 && forbidStyling &&
+                uri.equals(FormsConstants.INSTANCE_NS) && loc.equals("styling")) {
+                throw new SAXException("Cannot use 'fi:*' attributes and <fi:styling> at the same time");
+            }
+
+            depth++;
+        }
+
+        public void endElement(String uri, String loc, String raw)
+        throws SAXException {
+            depth--;
+            if (depth > 0) {
+                // Propagate all but root element
+                super.endElement(uri, loc, raw);
+            }
+        }
+
+        public void flushRoot() throws SAXException {
+            if (depth != 0) {
+                throw new IllegalStateException("Depth is not zero");
+            }
+            super.endElement(this.rootUri, this.rootLoc, this.rootRaw);
+        }
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/generation/JXMacrosHelper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/generation/SelectionListFilter.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/generation/SelectionListFilter.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/generation/SelectionListFilter.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/generation/SelectionListFilter.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,69 @@
+/*
+ * Copyright 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.generation;
+
+import org.apache.cocoon.forms.FormsConstants;
+import org.apache.cocoon.xml.AbstractXMLPipe;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * A filter for selection lists, that keeps only those items that start with a given filter value.
+ *
+ * @since 2.1.8
+ * @version $Id: SelectionListFilter.java 326838 2005-10-20 06:26:53Z sylvain $
+ */
+public class SelectionListFilter extends AbstractXMLPipe {
+    
+    private ContentHandler next;
+    private int filterDepth = 0;
+    private int depth = 0;
+    private String filterValue;
+    private static final ContentHandler NULL_HANDLER = new DefaultHandler();
+
+    public SelectionListFilter(String filterValue, ContentHandler next) {
+        this.next = next;
+        this.setContentHandler(next);
+        this.filterValue = filterValue;
+    }
+    
+    public void startElement(String uri, String loc, String raw, Attributes a) throws SAXException {
+        depth++;
+
+        if (uri.equals(FormsConstants.INSTANCE_NS) && loc.equals("item")) {
+            String value = a.getValue("value");
+            if (!value.startsWith(this.filterValue)) {
+                filterDepth = depth;
+                setContentHandler(NULL_HANDLER);
+            }
+        }
+
+        super.startElement(uri, loc, raw, a);
+    }
+    
+    public void endElement(String uri, String loc, String raw) throws SAXException {
+        super.endElement(uri, loc, raw);
+        
+        if (depth == filterDepth) {
+            filterDepth = 0;
+            setContentHandler(this.next);
+        }
+
+        depth--;
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/generation/SelectionListFilter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/generation/SuggestionListGenerator.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/generation/SuggestionListGenerator.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/generation/SuggestionListGenerator.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/generation/SuggestionListGenerator.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,106 @@
+/*
+ * Copyright 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.generation;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.components.flow.ContinuationsManager;
+import org.apache.cocoon.components.flow.InvalidContinuationException;
+import org.apache.cocoon.components.flow.WebContinuation;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.forms.FormsConstants;
+import org.apache.cocoon.forms.datatype.SelectionList;
+import org.apache.cocoon.forms.formmodel.Field;
+import org.apache.cocoon.forms.formmodel.Form;
+import org.apache.cocoon.generation.ServiceableGenerator;
+import org.apache.cocoon.sitemap.SitemapParameters;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+/**
+ * A generator for suggestion lists.
+ *
+ * @since 2.1.8
+ * @version $Id: SuggestionListGenerator.java 326838 2005-10-20 06:26:53Z sylvain $
+ */
+public class SuggestionListGenerator extends ServiceableGenerator {
+
+    private ContinuationsManager contManager;
+    private WebContinuation wk;
+    private SelectionList list;
+    private String filter;
+    private Locale locale;
+
+    public void service(ServiceManager manager) throws ServiceException {
+        super.service(manager);
+        this.contManager = (ContinuationsManager)manager.lookup(ContinuationsManager.ROLE);
+    }
+
+    public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException {
+        super.setup(resolver, objectModel, src, par);
+        
+        Request req = ObjectModelHelper.getRequest(objectModel);
+        
+        String continuationId = par.getParameter("continuation-id", req.getParameter("continuation-id"));
+        String widgetPath = par.getParameter("widget-id", req.getParameter("widget-id")).replace('.', '/');
+        String widgetId = widgetPath.replace('/', '.');
+        this.filter = par.getParameter("filter", req.getParameter(widgetId));
+        
+        // The interpreter id is the sitemap's URI
+        String interpreterId = SitemapParameters.getLocation(parameters).getURI();
+        wk = this.contManager.lookupWebContinuation(continuationId, interpreterId);
+        if (wk == null || wk.disposed()) {
+            throw new InvalidContinuationException("Cannot get continuation for suggestion list");
+        }
+        
+        Form form = (Form)wk.getAttribute("form");
+        if (form == null) {
+            throw new ProcessingException("No form is attached to the continuation");
+        }
+        
+        this.locale = form.getLocale();
+        
+        Field field = (Field)form.lookupWidget(widgetPath);
+        list = field.getSuggestionList();
+        if (list == null) {
+            throw new ProcessingException(field + " has no suggestion list");
+        }
+    }
+    
+    public void generate() throws IOException, SAXException, ProcessingException {
+        super.contentHandler.startDocument();
+        super.contentHandler.startPrefixMapping(FormsConstants.INSTANCE_PREFIX, FormsConstants.INSTANCE_NS);
+        ContentHandler handler;
+        if (filter == null || filter.length() == 0) {
+            handler = super.contentHandler;
+        } else {
+            handler = new SelectionListFilter(filter, super.contentHandler);
+        }
+        list.generateSaxFragment(handler, this.locale);
+        
+        super.contentHandler.endPrefixMapping(FormsConstants.INSTANCE_PREFIX);
+        super.contentHandler.endDocument();
+    }
+
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/generation/SuggestionListGenerator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/transformation/EffectPipe.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/transformation/EffectPipe.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/transformation/EffectPipe.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/transformation/EffectPipe.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,585 @@
+/*
+ * 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.cocoon.xml.AbstractXMLPipe;
+import org.apache.cocoon.xml.SaxBuffer;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.LocatorImpl;
+
+import java.util.LinkedList;
+
+/**
+ * Base class for XMLPipe's. Allows the structure of the source code of
+ * the XMLPipe to match the structure of the data being transformed.
+ *
+ * @version $Id: EffectPipe.java 289538 2005-09-16 13:46:22Z sylvain $
+ */
+public class EffectPipe extends AbstractXMLPipe {
+
+    /**
+     * Handler interface. Accepts SAX events, can return other handler
+     * to replace self for further events.
+     */
+    protected interface Handler {
+        public Handler startDocument()
+        throws SAXException;
+
+        public void endDocument()
+        throws SAXException;
+
+        public void startPrefixMapping(String prefix, String uri)
+        throws SAXException;
+
+        public void endPrefixMapping(String prefix)
+        throws SAXException;
+
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException;
+
+        /**
+         * Called before startElement, handler can decide what other handler should process
+         * next startElement.
+         */
+        public Handler nestedElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException;
+
+        public void endElement(String uri, String loc, String raw)
+        throws SAXException;
+
+        public Handler characters(char ch[], int start, int length)
+        throws SAXException;
+
+        public Handler ignorableWhitespace(char ch[], int start, int length)
+        throws SAXException;
+
+        public Handler processingInstruction(String target, String data)
+        throws SAXException;
+
+        public Handler skippedEntity(String name)
+        throws SAXException;
+
+        public Handler startDTD(String name, String publicId, String systemId)
+        throws SAXException;
+
+        public Handler endDTD()
+        throws SAXException;
+
+        public Handler startEntity(String name)
+        throws SAXException;
+
+        public Handler endEntity(String name)
+        throws SAXException;
+
+        public Handler startCDATA()
+        throws SAXException;
+
+        public Handler endCDATA()
+        throws SAXException;
+
+        public Handler comment(char c[], int start, int len)
+        throws SAXException;
+    }
+
+    /**
+     * Ignores all events
+     */
+    protected class NullHandler implements Handler {
+        public Handler startDocument() throws SAXException {
+            return this;
+        }
+
+        public void endDocument() throws SAXException {
+        }
+
+        public void startPrefixMapping(String prefix, String uri) throws SAXException {
+        }
+
+        public void endPrefixMapping(String prefix) throws SAXException {
+        }
+
+        public Handler nestedElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
+            return this;
+        }
+
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
+            return this;
+        }
+
+        public void endElement(String uri, String loc, String raw) throws SAXException {
+        }
+
+        public Handler characters(char ch[], int start, int length) throws SAXException {
+            return this;
+        }
+
+        public Handler ignorableWhitespace(char ch[], int start, int length) throws SAXException {
+            return this;
+        }
+
+        public Handler processingInstruction(String target, String data) throws SAXException {
+            return this;
+        }
+
+        public Handler skippedEntity(String name) throws SAXException {
+            return this;
+        }
+
+        public Handler startDTD(String name, String publicId, String systemId) throws SAXException {
+            return this;
+        }
+
+        public Handler endDTD() throws SAXException {
+            return this;
+        }
+
+        public Handler startEntity(String name) throws SAXException {
+            return this;
+        }
+
+        public Handler endEntity(String name) throws SAXException {
+            return this;
+        }
+
+        public Handler startCDATA() throws SAXException {
+            return this;
+        }
+
+        public Handler endCDATA() throws SAXException {
+            return this;
+        }
+
+        public Handler comment(char c[], int start, int len) throws SAXException {
+            return this;
+        }
+    }
+
+    /**
+     * Buffers content into the pipe's SAX buffer.
+     */
+    protected class BufferHandler extends NullHandler {
+        public Handler startDocument() throws SAXException {
+            if (buffer != null) buffer.startDocument();
+            return this;
+        }
+
+        public void setDocumentLocator(Locator paramLocator) {
+            locator = new LocatorImpl(paramLocator);
+            if (buffer != null) buffer.setDocumentLocator(paramLocator);
+        }
+
+        public void endDocument() throws SAXException {
+            if (buffer != null) buffer.endDocument();
+        }
+
+        public void startPrefixMapping(String prefix, String uri) throws SAXException {
+            if (buffer != null) buffer.startPrefixMapping(prefix, uri);
+        }
+
+        public void endPrefixMapping(String prefix) throws SAXException {
+            if (buffer != null) buffer.endPrefixMapping(prefix);
+        }
+
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
+            if (buffer != null) buffer.startElement(uri, loc, raw, attrs);
+            return this;
+        }
+
+        public void endElement(String uri, String loc, String raw) throws SAXException {
+            if (buffer != null) buffer.endElement(uri, loc, raw);
+        }
+
+        public Handler characters(char ch[], int start, int length) throws SAXException {
+            if (buffer != null) buffer.characters(ch, start, length);
+            return this;
+        }
+
+        public Handler ignorableWhitespace(char ch[], int start, int length) throws SAXException {
+            if (buffer != null) buffer.ignorableWhitespace(ch, start, length);
+            return this;
+        }
+
+        public Handler processingInstruction(String target, String data) throws SAXException {
+            if (buffer != null) buffer.processingInstruction(target, data);
+            return this;
+        }
+
+        public Handler skippedEntity(String name) throws SAXException {
+            if (buffer != null) buffer.skippedEntity(name);
+            return this;
+        }
+
+        public Handler startDTD(String name, String publicId, String systemId) throws SAXException {
+            if (buffer != null) buffer.startDTD(name, publicId, systemId);
+            return this;
+        }
+
+        public Handler endDTD() throws SAXException {
+            if (buffer != null) buffer.endDTD();
+            return this;
+        }
+
+        public Handler startEntity(String name) throws SAXException {
+            if (buffer != null) buffer.startEntity(name);
+            return this;
+        }
+
+        public Handler endEntity(String name) throws SAXException {
+            if (buffer != null) buffer.endEntity(name);
+            return this;
+        }
+
+        public Handler startCDATA() throws SAXException {
+            if (buffer != null) buffer.startCDATA();
+            return this;
+        }
+
+        public Handler endCDATA() throws SAXException {
+            if (buffer != null) buffer.endCDATA();
+            return this;
+        }
+
+        public Handler comment(char c[], int start, int len) throws SAXException {
+            if (buffer != null) buffer.comment(c, start, len);
+            return this;
+        }
+    }
+
+    /**
+     * Copies events over into the contentHandler
+     */
+    protected class CopyHandler extends NullHandler {
+        public Handler startDocument() throws SAXException {
+            contentHandler.startDocument();
+            return this;
+        }
+
+        public void endDocument() throws SAXException {
+            contentHandler.endDocument();
+        }
+
+        public void startPrefixMapping(String prefix, String uri) throws SAXException {
+            contentHandler.startPrefixMapping(prefix, uri);
+        }
+
+        public void endPrefixMapping(String prefix) throws SAXException {
+            contentHandler.endPrefixMapping(prefix);
+        }
+
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
+            contentHandler.startElement(uri, loc, raw, attrs);
+            return this;
+        }
+
+        public void endElement(String uri, String loc, String raw) throws SAXException {
+            contentHandler.endElement(uri, loc, raw);
+        }
+
+        public Handler characters(char ch[], int start, int length) throws SAXException {
+            contentHandler.characters(ch, start, length);
+            return this;
+        }
+
+        public Handler ignorableWhitespace(char ch[], int start, int length) throws SAXException {
+            contentHandler.ignorableWhitespace(ch, start, length);
+            return this;
+        }
+
+        public Handler processingInstruction(String target, String data) throws SAXException {
+            contentHandler.processingInstruction(target, data);
+            return this;
+        }
+
+        public Handler skippedEntity(String name) throws SAXException {
+            contentHandler.skippedEntity(name);
+            return this;
+        }
+
+        public Handler startDTD(String name, String publicId, String systemId) throws SAXException {
+            if (lexicalHandler != null) lexicalHandler.startDTD(name, publicId, systemId);
+            return this;
+        }
+
+        public Handler endDTD() throws SAXException {
+            if (lexicalHandler != null) lexicalHandler.endDTD();
+            return this;
+        }
+
+        public Handler startEntity(String name) throws SAXException {
+            if (lexicalHandler != null) lexicalHandler.startEntity(name);
+            return this;
+        }
+
+        public Handler endEntity(String name) throws SAXException {
+            if (lexicalHandler != null) lexicalHandler.endEntity(name);
+            return this;
+        }
+
+        public Handler startCDATA() throws SAXException {
+            if (lexicalHandler != null) lexicalHandler.startCDATA();
+            return this;
+        }
+
+        public Handler endCDATA() throws SAXException {
+            if (lexicalHandler != null) lexicalHandler.endCDATA();
+            return this;
+        }
+
+        public Handler comment(char c[], int start, int len) throws SAXException {
+            if (lexicalHandler != null) lexicalHandler.comment(c, start, len);
+            return this;
+        }
+    }
+
+    /**
+     * Throws exception on most events, with the exception of ignorableWhitespace.
+     */
+    protected class ErrorHandler extends NullHandler {
+        protected String getName() {
+            return "<unknown>";
+        }
+
+        public Handler startDocument() throws SAXException {
+            throw new SAXException("Unexpected startDocument in '" + getName() + "' (" + getLocation() + ")");
+        }
+
+        public void endDocument() throws SAXException {
+            throw new SAXException("Unexpected endDocument in '" + getName() + "' (" + getLocation() + ")");
+        }
+
+        public void startPrefixMapping(String prefix, String uri) throws SAXException {
+            throw new SAXException("Unexpected startPrefixMapping in '" + getName() + "' (" + getLocation() + ")");
+        }
+
+        public void endPrefixMapping(String prefix) throws SAXException {
+            throw new SAXException("Unexpected endPrefixMapping in '" + getName() + "' (" + getLocation() + ")");
+        }
+
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
+            throw new SAXException("Unexpected startElement in '" + getName() + "' (" + getLocation() + ")");
+        }
+
+        public void endElement(String uri, String loc, String raw) throws SAXException {
+            throw new SAXException("Unexpected endElement in '" + getName() + "' (" + getLocation() + ")");
+        }
+
+        public Handler characters(char ch[], int start, int length) throws SAXException {
+            throw new SAXException("Unexpected characters in '" + getName() + "' (" + getLocation() + ")");
+        }
+
+        public Handler processingInstruction(String target, String data) throws SAXException {
+            throw new SAXException("Unexpected processingInstruction in '" + getName() + "' (" + getLocation() + ")");
+        }
+
+        public Handler skippedEntity(String name) throws SAXException {
+            throw new SAXException("Unexpected skippedEntity in '" + getName() + "' (" + getLocation() + ")");
+        }
+
+        public Handler startDTD(String name, String publicId, String systemId) throws SAXException {
+            throw new SAXException("Unexpected startDTD in '" + getName() + "' (" + getLocation() + ")");
+        }
+
+        public Handler endDTD() throws SAXException {
+            throw new SAXException("Unexpected endDTD in '" + getName() + "' (" + getLocation() + ")");
+        }
+
+        public Handler startEntity(String name) throws SAXException {
+            throw new SAXException("Unexpected startEntity in '" + getName() + "' (" + getLocation() + ")");
+        }
+
+        public Handler endEntity(String name) throws SAXException {
+            throw new SAXException("Unexpected endEntity in '" + getName() + "' (" + getLocation() + ")");
+        }
+
+        public Handler startCDATA() throws SAXException {
+            throw new SAXException("Unexpected startCDATA in '" + getName() + "' (" + getLocation() + ")");
+        }
+
+        public Handler endCDATA() throws SAXException {
+            throw new SAXException("Unexpected endCDATA in '" + getName() + "' (" + getLocation() + ")");
+        }
+
+        public Handler comment(char c[], int start, int len) throws SAXException {
+            throw new SAXException("Unexpected comment in '" + getName() + "' (" + getLocation() + ")");
+        }
+    }
+
+    protected final Handler hNull = new NullHandler();
+    protected final Handler hBuffer = new BufferHandler();
+
+    private Locator locator;
+    private LinkedList handlers;
+    private Handler handler;
+
+    private LinkedList buffers;
+    private LinkedList locators;
+    private SaxBuffer buffer;
+
+
+    /**
+     * Initialize the pipe before starting processing
+     */
+    protected void init(Handler top) {
+        locators = new LinkedList();
+        handlers = new LinkedList();
+        handler = top;
+    }
+
+    /**
+     * Recycle the pipe after processing
+     */
+    public void recycle() {
+        super.recycle();
+        handlers = null;
+        handler = null;
+        buffers = null;
+        buffer = null;
+        locator = null;
+        locators = null;
+    }
+
+    /**
+     * @return current location (if known)
+     */
+    protected String getLocation() {
+        if (locator == null) {
+            return "unknown";
+        }
+
+        final String location = " (" + locator.getSystemId() + ":" +
+                                       locator.getLineNumber() + ":" +
+                                       locator.getColumnNumber() + ")";
+        return location;
+    }
+
+    protected void pushHandler(Handler handler) {
+        this.handlers.addFirst(this.handler);
+        this.handler = handler;
+    }
+
+    protected void popHandler() {
+        this.handler = (Handler) this.handlers.removeFirst();
+    }
+
+    protected void beginBuffer() {
+        if (this.buffer != null) {
+            if (this.buffers == null) {
+                this.buffers = new LinkedList();
+            }
+            this.buffers.addFirst(this.buffer);
+        }
+        locators.addFirst(locator);
+        locator = new LocatorImpl(locator);
+        this.buffer = new SaxBuffer();
+    }
+
+    protected SaxBuffer endBuffer() {
+        SaxBuffer buffer = this.buffer;
+        if (this.buffers != null && this.buffers.size() > 0) {
+            this.buffer = (SaxBuffer) this.buffers.removeFirst();
+        } else {
+            this.buffer = null;
+        }
+        locator = (Locator)locators.removeFirst();
+        return buffer;
+    }
+
+    //
+    // ContentHandler methods
+    //
+
+    public void setDocumentLocator(Locator locator) {
+        this.locator = locator;
+    }
+
+    public void startDocument() throws SAXException {
+        pushHandler(handler.startDocument());
+    }
+
+    public void endDocument() throws SAXException {
+        handler.endDocument();
+        popHandler();
+    }
+
+    public void startPrefixMapping(String prefix, String uri) throws SAXException {
+        handler.startPrefixMapping(prefix, uri);
+    }
+
+    public void endPrefixMapping(String prefix) throws SAXException {
+        handler.endPrefixMapping(prefix);
+    }
+
+    public void startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
+        pushHandler(handler.nestedElement(uri, loc, raw, attrs));
+        handler = handler.startElement(uri, loc, raw, attrs);
+    }
+
+    public void endElement(String uri, String loc, String raw) throws SAXException {
+        handler.endElement(uri, loc, raw);
+        popHandler();
+    }
+
+    public void characters(char ch[], int start, int len) throws SAXException {
+        handler = handler.characters(ch, start, len);
+    }
+
+    public void ignorableWhitespace(char ch[], int start, int len) throws SAXException {
+        handler = handler.ignorableWhitespace(ch, start, len);
+    }
+
+    public void processingInstruction(String target, String data) throws SAXException {
+        handler = handler.processingInstruction(target, data);
+    }
+
+    public void skippedEntity(String name) throws SAXException {
+        handler = handler.skippedEntity(name);
+    }
+
+    //
+    // LexicalHandler methods
+    //
+
+    public void startDTD(String name, String publicId, String systemId) throws SAXException {
+        handler = handler.startDTD(name, publicId, systemId);
+    }
+
+    public void endDTD() throws SAXException {
+        handler = handler.endDTD();
+    }
+
+    public void startEntity(String name) throws SAXException {
+        handler = handler.startEntity(name);
+    }
+
+    public void endEntity(String name) throws SAXException {
+        handler = handler.endEntity(name);
+    }
+
+    public void startCDATA() throws SAXException {
+        handler = handler.startCDATA();
+    }
+
+    public void endCDATA() throws SAXException {
+        handler = handler.endCDATA();
+    }
+
+    public void comment(char ch[], int start, int len) throws SAXException {
+        handler = handler.comment(ch, start, len);
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/transformation/EffectPipe.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/transformation/EffectWidgetReplacingPipe.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/transformation/EffectWidgetReplacingPipe.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/transformation/EffectWidgetReplacingPipe.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/transformation/EffectWidgetReplacingPipe.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,940 @@
+/*
+ * 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.excalibur.pool.Recyclable;
+
+import org.apache.cocoon.forms.FormsConstants;
+import org.apache.cocoon.forms.formmodel.AggregateField;
+import org.apache.cocoon.forms.formmodel.DataWidget;
+import org.apache.cocoon.forms.formmodel.Group;
+import org.apache.cocoon.forms.formmodel.Repeater;
+import org.apache.cocoon.forms.formmodel.Struct;
+import org.apache.cocoon.forms.formmodel.Union;
+import org.apache.cocoon.forms.formmodel.Widget;
+import org.apache.cocoon.forms.validation.ValidationError;
+import org.apache.cocoon.forms.validation.ValidationErrorAware;
+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.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
+import org.xml.sax.helpers.AttributesImpl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * The basic operation of this Pipe is that it replaces <code>ft:widget</code>
+ * (in the {@link FormsConstants#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 FormsConstants#INSTANCE_NS "CForms Instance"}
+ * namespace), can then be translated to a HTML presentation by an XSLT.
+ * This XSLT 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 $Id: EffectWidgetReplacingPipe.java 326838 2005-10-20 06:26:53Z sylvain $
+ */
+public class EffectWidgetReplacingPipe extends EffectPipe {
+
+    /**
+     * Form location attribute on <code>ft:form-template</code> element, containing
+     * JXPath expression which should result in Form object.
+     *
+     * @see FormsPipelineConfig#findForm(String)
+     */
+    private static final String LOCATION = "location";
+
+    private static final String AGGREGATE_WIDGET = "aggregate-widget";
+    private static final String CHOOSE = "choose";
+    private static final String CLASS = "class";
+    private static final String CONTINUATION_ID = "continuation-id";
+    private static final String FORM_TEMPLATE_EL = "form-template";
+    private static final String GROUP = "group";
+    private static final String NEW = "new";
+    private static final String REPEATER_SIZE = "repeater-size";
+    private static final String REPEATER_WIDGET = "repeater-widget";
+    private static final String REPEATER_WIDGET_LABEL = "repeater-widget-label";
+    private static final String STRUCT = "struct";
+    private static final String STYLING_EL = "styling";
+    private static final String UNION = "union";
+    private static final String VALIDATION_ERROR = "validation-error";
+    private static final String WIDGET = "widget";
+    private static final String WIDGET_LABEL = "widget-label";
+
+    private final AggregateWidgetHandler           hAggregate       = new AggregateWidgetHandler();
+    private final ChooseHandler                    hChoose          = new ChooseHandler();
+    private final ChoosePassThruHandler            hChoosePassThru  = new ChoosePassThruHandler();
+    private final ClassHandler                     hClass           = new ClassHandler();
+    private final ContinuationIdHandler            hContinuationId  = new ContinuationIdHandler();
+    private final DocHandler                       hDocument        = new DocHandler();
+    private final FormHandler                      hForm            = new FormHandler();
+    private final GroupHandler                     hGroup           = new GroupHandler();
+    private final NestedHandler                    hNested          = new NestedHandler();
+    private final NewHandler                       hNew             = new NewHandler();
+    private final RepeaterSizeHandler              hRepeaterSize    = new RepeaterSizeHandler();
+    private final RepeaterWidgetHandler            hRepeaterWidget  = new RepeaterWidgetHandler();
+    private final RepeaterWidgetLabelHandler       hRepeaterWidgetLabel = new RepeaterWidgetLabelHandler();
+    private final SkipHandler                      hSkip            = new SkipHandler();
+    private final StructHandler                    hStruct          = new StructHandler();
+    private final StylingContentHandler            hStyling         = new StylingContentHandler();
+    private final UnionHandler                     hUnion           = new UnionHandler();
+    private final UnionPassThruHandler             hUnionPassThru   = new UnionPassThruHandler();
+    private final ValidationErrorHandler           hValidationError = new ValidationErrorHandler();
+    private final WidgetHandler                    hWidget          = new WidgetHandler();
+    private final WidgetLabelHandler               hWidgetLabel     = new WidgetLabelHandler();
+
+    /**
+     * Map containing all handlers
+     */
+    protected final Map templates;
+
+    protected FormsPipelineConfig pipeContext;
+
+    /**
+     * The namespaces and their prefixes
+     */
+    private final List namespaces;
+
+    /**
+     * True if instance namespace has been mapped to the
+     * 'fi' prefix.
+     */
+    private boolean hasInstanceNamespace;
+
+    protected Widget contextWidget;
+    protected LinkedList contextWidgets;
+    protected LinkedList chooseWidgets;
+    protected Widget widget;
+    protected Map classes;
+
+
+    public EffectWidgetReplacingPipe() {
+        namespaces = new ArrayList(5);
+        // Setup map of templates.
+        templates = new HashMap();
+        templates.put(AGGREGATE_WIDGET, hAggregate);
+        templates.put(CHOOSE, hChoose);
+        templates.put(CLASS, hClass);
+        templates.put(CONTINUATION_ID, hContinuationId);
+        templates.put(GROUP, hGroup);
+        templates.put(NEW, hNew);
+        templates.put(REPEATER_SIZE, hRepeaterSize);
+        templates.put(REPEATER_WIDGET, hRepeaterWidget);
+        templates.put(REPEATER_WIDGET_LABEL, hRepeaterWidgetLabel);
+        templates.put(STRUCT, hStruct);
+        templates.put(UNION, hUnion);
+        templates.put(VALIDATION_ERROR, hValidationError);
+        templates.put(WIDGET, hWidget);
+        templates.put(WIDGET_LABEL, hWidgetLabel);
+    }
+
+    public void init(Widget contextWidget, FormsPipelineConfig pipeContext) {
+        // Document handler is top level handler
+        super.init(hDocument);
+        this.pipeContext = pipeContext;
+
+        // Initialize widget related variables
+        this.contextWidgets = new LinkedList();
+        this.chooseWidgets = new LinkedList();
+        this.classes = new HashMap();
+    }
+
+    public void recycle() {
+        super.recycle();
+        this.contextWidget = null;
+        this.widget = null;
+        this.pipeContext = null;
+        this.namespaces.clear();
+        this.hasInstanceNamespace = false;
+    }
+
+    /**
+     * Get value of the required attribute
+     */
+    protected String getAttributeValue(String loc, Attributes attrs, String name) throws SAXException {
+        String value = attrs.getValue(name);
+        if (value == null) {
+            throw new SAXException("Element '" + loc + "' missing required '" + name + "' attribute, " +
+                                   "at " + getLocation());
+        }
+        return value;
+    }
+
+    /**
+     * Get non-empty value of the required attribute
+     */
+    protected String getRequiredAttributeValue(String loc, Attributes attrs, String name) throws SAXException {
+        String value = attrs.getValue(name);
+        if (value == null || value.equals("")) {
+            throw new SAXException("Element '" + loc + "' missing required '" + name + "' attribute, " +
+                                   "at " + getLocation());
+        }
+        return value;
+    }
+
+    /**
+     * Set the widget by the id attribute
+     */
+    protected void setWidget(String loc, Attributes attrs) throws SAXException {
+        setWidget(loc, getRequiredAttributeValue(loc, attrs, "id"));
+    }
+
+    /**
+     * Set the widget by its path
+     */
+    protected void setWidget(String loc, String path) throws SAXException {
+        widget = contextWidget.lookupWidget(path);
+        if (widget == null) {
+            if (contextWidget.getRequestParameterName().equals("")) {
+                throw new SAXException("Element '" + loc + "' refers to unexistent widget path '" + path + "', " +
+                                       "relative to the form container, at " + getLocation());
+            } else {
+                throw new SAXException("Element '" + loc + "' refers to unexistent widget path '" + path + "', " +
+                                       "relative to the '" + contextWidget.getRequestParameterName() + "', " +
+                                       "at " + getLocation());
+            }
+        }
+    }
+
+    /**
+     * Set typed widget by the id attribute
+     */
+    protected void setTypedWidget(String loc, Attributes attrs, Class wclass, String wname) throws SAXException {
+        setWidget(loc, attrs);
+        if (!wclass.isInstance(widget)) {
+            throw new SAXException("Element '" + loc + "' can only be used with " + wname + " widgets, " +
+                                   "at " + getLocation());
+        }
+    }
+
+    protected boolean isVisible(Widget widget) {
+        return widget.getCombinedState().isDisplayingValues();
+    }
+
+    /**
+     * Needed to get things working with JDK 1.3. Can be removed once we
+     * don't support that platform any more.
+     */
+    private ContentHandler getContentHandler() {
+        return this.contentHandler;
+    }
+
+    /**
+     * Needed to get things working with JDK 1.3. Can be removed once we
+     * don't support that platform any more.
+     */
+    private LexicalHandler getLexicalHandler() {
+        return this.lexicalHandler;
+    }
+
+
+    /**
+     * Process the SAX event.
+     * @see org.xml.sax.ContentHandler#startPrefixMapping
+     */
+    public void startPrefixMapping(String prefix, String uri)
+    throws SAXException {
+        if (prefix != null) {
+            this.namespaces.add(new String[] {prefix, uri});
+        }
+
+        // Consume template namespace mapping
+        if (!FormsConstants.TEMPLATE_NS.equals(uri)) {
+            super.startPrefixMapping(prefix, uri);
+        }
+    }
+
+    /**
+     * Process the SAX event.
+     * @see org.xml.sax.ContentHandler#endPrefixMapping
+     */
+    public void endPrefixMapping(String prefix)
+    throws SAXException {
+        String uri = null;
+
+        if (prefix != null) {
+            // Find and remove the namespace prefix
+            boolean found = false;
+            for (int i = this.namespaces.size() - 1; i >= 0; i--) {
+                final String[] prefixAndUri = (String[]) this.namespaces.get(i);
+                if (prefixAndUri[0].equals(prefix)) {
+                    uri = prefixAndUri[1];
+                    this.namespaces.remove(i);
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                throw new SAXException("Namespace for prefix '" + prefix + "' not found.");
+            }
+        }
+
+        // Consume template namespace mapping
+        if (!FormsConstants.TEMPLATE_NS.equals(uri)) {
+            super.endPrefixMapping(prefix);
+        }
+    }
+
+    /**
+     * @return True if prefix is already mapped into the namespace
+     */
+    protected boolean hasPrefixMapping(String uri, String prefix) {
+        final int l = this.namespaces.size();
+        for (int i = 0; i < l; i++) {
+            String[] prefixAndUri = (String[]) this.namespaces.get(i);
+            if (prefixAndUri[0].equals(prefix) && prefixAndUri[1].equals(uri)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    //
+    // Handler classes to transform CForms template elements
+    //
+
+    protected class NestedHandler extends CopyHandler {
+        public Handler nestedElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            // Is it forms namespace?
+            if (!FormsConstants.TEMPLATE_NS.equals(uri)) {
+                return hNested;
+            }
+
+            Handler handler = (Handler) templates.get(loc);
+            if (handler == null) {
+                throw new SAXException("Element '" + loc + "' was not recognized, " +
+                                       "at " + getLocation());
+            }
+
+            return handler;
+        }
+    }
+
+    /**
+     * Top level handler for the forms template
+     */
+    protected class DocHandler extends CopyHandler {
+        public Handler nestedElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            if (FormsConstants.TEMPLATE_NS.equals(uri)) {
+                if (!FORM_TEMPLATE_EL.equals(loc)) {
+                    throw new SAXException("Element '" + loc + "' is not permitted outside of " +
+                                           "'form-template', at " + getLocation());
+                }
+
+                return hForm;
+            }
+
+            return super.nestedElement(uri, loc, raw, attrs);
+        }
+    }
+
+    /**
+     * <code>ft:form-template</code> element handler.
+     * <pre>
+     * &lt;ft:form-template locale="..." location="..."&gt;
+     *   ...
+     * &lt;/ft:form-template&gt;
+     * </pre>
+     */
+    protected class FormHandler extends NestedHandler {
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            if (contextWidget != null) {
+                throw new SAXException("Element 'form-template' can not be nested, " +
+                                       "at " + getLocation());
+            }
+
+            AttributesImpl newAttrs = attrs == null || attrs.getLength() == 0?
+                    new AttributesImpl():
+                    new AttributesImpl(attrs);
+
+            // ====> Retrieve the form
+            String formLocation = attrs.getValue(LOCATION);
+            if (formLocation != null) {
+                // Remove the location attribute
+                newAttrs.removeAttribute(newAttrs.getIndex(LOCATION));
+            }
+            contextWidget = pipeContext.findForm(formLocation);
+
+            // ====> Check if form visible (and skip it if it's not)
+            if (!isVisible(contextWidget)) {
+                return hNull;
+            }
+
+            // ====> Determine the Locale
+            // TODO pull this locale stuff also up in the Config object?
+            String localeAttr = attrs.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());
+                }
+            }
+
+            // We need to merge input.attrs with possible overruling attributes
+            // from the pipeContext
+            pipeContext.addFormAttributes(newAttrs);
+            String[] namesToTranslate = {"action"};
+            Attributes transAttrs = null;
+            try {
+                transAttrs = translateAttributes(newAttrs, namesToTranslate);
+            } catch (RuntimeException e) {
+                throw new SAXException( e.getMessage() + " " +getLocation());
+            }
+            
+            hasInstanceNamespace = hasPrefixMapping(FormsConstants.INSTANCE_NS, FormsConstants.INSTANCE_PREFIX);
+            if (!hasInstanceNamespace) {
+                getContentHandler().startPrefixMapping(FormsConstants.INSTANCE_PREFIX, FormsConstants.INSTANCE_NS);
+            }
+            getContentHandler().startElement(FormsConstants.INSTANCE_NS, "form-template", FormsConstants.INSTANCE_PREFIX_COLON + "form-template", transAttrs);
+            return this;
+        }
+
+        public void endElement(String uri, String loc, String raw)
+        throws SAXException {
+            getContentHandler().endElement(FormsConstants.INSTANCE_NS, "form-template", FormsConstants.INSTANCE_PREFIX_COLON + "form-template");
+            if (!hasInstanceNamespace) {
+                getContentHandler().endPrefixMapping(FormsConstants.INSTANCE_PREFIX);
+            }
+            contextWidget = null;
+        }
+    }
+
+    /**
+     * <code>ft:choose</code>, <code>ft:union</code> use this.
+     */
+    protected class SkipHandler extends NestedHandler {
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            return this;
+        }
+
+        public void endElement(String uri, String loc, String raw)
+        throws SAXException {
+        }
+    }
+
+    //
+    // Widget Handlers
+    //
+
+    /**
+     * Handles <code>ft:widget-label</code> element.
+     */
+    protected class WidgetLabelHandler extends ErrorHandler {
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            setWidget(loc, attrs);
+            widget.generateLabel(getContentHandler());
+            return this;
+        }
+
+        public void endElement(String uri, String loc, String raw)
+        throws SAXException {
+        }
+    }
+
+    /**
+     * Handles <code>ft:widget</code> element.
+     */
+    protected class WidgetHandler extends NullHandler {
+        // Widgets can't be nested, so this variable is Ok
+        private boolean hasStyling;
+
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            setWidget(loc, attrs);
+            if (!isVisible(widget)) {
+                return hNull;
+            }
+
+            hasStyling = false;
+            return this;
+        }
+
+        public Handler nestedElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            if (FormsConstants.INSTANCE_NS.equals(uri)) {
+                if (!STYLING_EL.equals(loc)) {
+                    throw new SAXException("Element '" + loc + "' is not permitted within 'widget', " +
+                                           "at " + getLocation());
+                }
+                hasStyling = true;
+                beginBuffer();
+                // Buffer styling elements
+                return hBuffer;
+            }
+            return hNull;
+        }
+
+        public void endElement(String uri, String loc, String raw)
+        throws SAXException {
+            if (hasStyling) {
+                // Pipe widget XML through the special handler to insert styling element
+                // before fi:widget end element.
+                hasStyling = false;
+                hStyling.recycle();
+                hStyling.setSaxFragment(endBuffer());
+                hStyling.setContentHandler(getContentHandler());
+                hStyling.setLexicalHandler(getLexicalHandler());
+                widget.generateSaxFragment(hStyling, pipeContext.getLocale());
+            } else {
+                // Pipe widget XML directly into the output handler
+                widget.generateSaxFragment(getContentHandler(), pipeContext.getLocale());
+            }
+            widget = null;
+        }
+    }
+
+    //
+    // Repeater Handlers
+    //
+
+    /**
+     * Handles <code>ft:repeater-size</code> element.
+     */
+    protected class RepeaterSizeHandler extends ErrorHandler {
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            setTypedWidget(loc, attrs, Repeater.class, "repeater");
+            ((Repeater) widget).generateSize(getContentHandler());
+            widget = null;
+            return this;
+        }
+
+        public void endElement(String uri, String loc, String raw)
+        throws SAXException {
+        }
+    }
+
+    /**
+     * Handles <code>ft:repeater-widget-label</code> element.
+     */
+    protected class RepeaterWidgetLabelHandler extends ErrorHandler {
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            setTypedWidget(loc, attrs, Repeater.class, "repeater");
+            String path = getRequiredAttributeValue(loc, attrs, "widget-id");
+            ((Repeater) widget).generateWidgetLabel(path, getContentHandler());
+            widget = null;
+            return this;
+        }
+
+        public void endElement(String uri, String loc, String raw)
+        throws SAXException {
+        }
+    }
+
+    /**
+     * Handles <code>ft:repeater</code> element.
+     */
+    protected class RepeaterWidgetHandler extends BufferHandler {
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            setTypedWidget(loc, attrs, Repeater.class, "repeater");
+            if (isVisible(widget)) {
+                beginBuffer();
+                return this;
+            }
+            return hNull;
+        }
+
+        public Handler nestedElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            return hBuffer;
+        }
+
+        public void endElement(String uri, String loc, String raw)
+        throws SAXException {
+            SaxBuffer buffer = endBuffer();
+            final Repeater repeater = (Repeater) widget;
+            final int rowCount = repeater.getSize();
+            pushHandler(hNested);
+            contextWidgets.addFirst(contextWidget);
+            for (int i = 0; i < rowCount; i++) {
+                contextWidget = repeater.getRow(i);
+                if (isVisible(contextWidget)) {
+                    buffer.toSAX(EffectWidgetReplacingPipe.this);
+                }
+            }
+            contextWidget = (Widget) contextWidgets.removeFirst();
+            popHandler();
+            widget = null;
+        }
+    }
+
+    //
+    // Grouping widgets Handlers
+    //
+
+    /**
+     * Handles <code>ft:group</code> element.
+     */
+    protected class GroupHandler extends NestedHandler {
+        protected Class getWidgetClass() {
+            return Group.class;
+        }
+
+        protected String getWidgetName() {
+            return "group";
+        }
+
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            setTypedWidget(loc, attrs, getWidgetClass(), getWidgetName());
+            if (!isVisible(widget)) {
+                return hNull;
+            }
+
+            contextWidgets.addFirst(contextWidget);
+            contextWidget = widget;
+            return this;
+        }
+
+        public void endElement(String uri, String loc, String raw)
+        throws SAXException {
+            contextWidget = (Widget) contextWidgets.removeFirst();
+        }
+    }
+
+    /**
+     * Handles <code>ft:aggregate</code> element.
+     */
+    protected class AggregateWidgetHandler extends GroupHandler {
+        protected Class getWidgetClass() {
+            return AggregateField.class;
+        }
+
+        protected String getWidgetName() {
+            return "aggregate";
+        }
+    }
+
+    /**
+     * Handles <code>ft:choose</code> element.
+     */
+    protected class ChooseHandler extends CopyHandler {
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
+            setWidget(loc, getRequiredAttributeValue(loc, attrs, "path"));
+            // TODO: Should instead check for datatype convertable to String.
+            if (!(widget instanceof DataWidget)) {
+                throw new SAXException("Element '" + loc + "' can only be used with DataWidget widgets, " +
+                                       "at " + getLocation());
+            }
+            // Choose does not change the context widget like Union does.
+            chooseWidgets.addFirst(widget);
+            return this;
+        }
+
+        public Handler nestedElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
+            if (FormsConstants.TEMPLATE_NS.equals(uri)) {
+                if ("when".equals(loc)) {
+                    String testValue = getAttributeValue(loc, attrs, "value");
+                    String value = (String) ((Widget) chooseWidgets.get(0)).getValue();
+                    return testValue.equals(value) ? hSkip : hNull;
+                }
+                throw new SAXException("Element '" + loc + "' is not permitted within 'choose', " +
+                                       "at " + getLocation());
+            }
+            return hChoosePassThru;
+        }
+
+        public void endElement(String uri, String loc, String raw) throws SAXException {
+            chooseWidgets.removeFirst();
+        }
+    }
+
+    /**
+     * Handles <code>ft:choose/ft:when</code> element.
+     */
+    protected class ChoosePassThruHandler extends CopyHandler {
+        public Handler nestedElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
+            if (FormsConstants.TEMPLATE_NS.equals(uri)) {
+                if ("when".equals(loc)) {
+                    String testValue = getAttributeValue(loc, attrs, "value");
+                    String value = (String) ((Widget) chooseWidgets.get(0)).getValue();
+                    return testValue.equals(value)?  hSkip: hNull;
+                }
+                throw new SAXException("Element '" + loc + "' is not permitted within 'choose', " +
+                                       "at " + getLocation());
+            }
+            return this;
+        }
+    }
+
+    /**
+     * Handles <code>ft:struct</code> element.
+     */
+    protected class StructHandler extends GroupHandler {
+        protected Class getWidgetClass() {
+            return Struct.class;
+        }
+
+        protected String getWidgetName() {
+            return "struct";
+        }
+    }
+
+    /**
+     * Handles <code>ft:union</code> element.
+     */
+    protected class UnionHandler extends GroupHandler {
+        protected Class getWidgetClass() {
+            return Union.class;
+        }
+
+        protected String getWidgetName() {
+            return "union";
+        }
+
+        public Handler nestedElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            if (FormsConstants.TEMPLATE_NS.equals(uri)) {
+                if ("case".equals(loc)) {
+                    String id = getAttributeValue(loc, attrs, "id");
+                    String value = (String) contextWidget.getValue();
+                    if (id.equals(value != null ? value : "")) {
+                        return hSkip;
+                    }
+                    return hNull;
+                }
+                throw new SAXException("Element '" + loc + "' is not permitted within 'union', " +
+                                       "at " + getLocation());
+            }
+            return hUnionPassThru;
+        }
+    }
+
+    /**
+     * Handles <code>ft:union/ft:case</code> element.
+     */
+    protected class UnionPassThruHandler extends CopyHandler {
+        public Handler nestedElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            if (FormsConstants.TEMPLATE_NS.equals(uri)) {
+                if ("case".equals(loc)) {
+                    if (contextWidget.getValue().equals(attrs.getValue("id"))) {
+                        return hSkip;
+                    }
+                    return hNull;
+                }
+                throw new SAXException("Element '" + loc + "' is not permitted within 'union', " +
+                                       "at " + getLocation());
+            }
+            return this;
+        }
+    }
+
+    /**
+     * Handles <code>ft:new</code> element.
+     */
+    protected class NewHandler extends CopyHandler {
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            String id = getRequiredAttributeValue(loc, attrs, "id");
+            SaxBuffer buffer = (SaxBuffer) classes.get(id);
+            if (buffer == null) {
+                throw new SAXException("New: Class '" + id + "' does not exist, " +
+                                       "at " + getLocation());
+            }
+            pushHandler(hNested);
+            buffer.toSAX(EffectWidgetReplacingPipe.this);
+            popHandler();
+            return this;
+        }
+
+        public Handler nestedElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            return hNull;
+        }
+
+        public void endElement(String uri, String loc, String raw)
+        throws SAXException {
+        }
+    }
+
+    /**
+     * Handles <code>ft:class</code> element.
+     * <pre>
+     * &lt;ft:class id="..."&gt;
+     *   ...
+     * &lt;/ft:class&gt;
+     * </pre>
+     */
+    protected class ClassHandler extends BufferHandler {
+        // FIXME What if <class> is nested within <class>?
+        private String widgetPath;
+
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            widgetPath = getRequiredAttributeValue(loc, attrs, "id");
+            beginBuffer();
+            return this;
+        }
+
+        public Handler nestedElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            return hBuffer;
+        }
+
+        public void endElement(String uri, String loc, String raw) throws SAXException {
+            classes.put(widgetPath, endBuffer());
+        }
+    }
+
+    /**
+     * Handles <code>ft:continuation-id</code> element.
+     * <pre>
+     * &lt;ft:continuation-id/&gt;
+     * </pre>
+     */
+    protected class ContinuationIdHandler extends ErrorHandler {
+        protected String getName() {
+            return "continuation-id";
+        }
+
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            // Insert the continuation id
+            // FIXME(SW) we could avoid costly JXPath evaluation if we had the objectmodel here.
+            Object idObj = pipeContext.evaluateExpression("$cocoon/continuation/id");
+            if (idObj == null) {
+                throw new SAXException("No continuation found");
+            }
+
+            String id = idObj.toString();
+            getContentHandler().startElement(FormsConstants.INSTANCE_NS, "continuation-id", FormsConstants.INSTANCE_PREFIX_COLON + "continuation-id", attrs);
+            getContentHandler().characters(id.toCharArray(), 0, id.length());
+            getContentHandler().endElement(FormsConstants.INSTANCE_NS, "continuation-id", FormsConstants.INSTANCE_PREFIX_COLON + "continuation-id");
+            return this;
+        }
+
+        public void endElement(String uri, String loc, String raw) throws SAXException {
+        }
+    }
+
+    /**
+     * This ContentHandler helps in inserting SAX events before the closing tag of the root
+     * element.
+     */
+    protected class StylingContentHandler extends AbstractXMLPipe
+                                          implements Recyclable {
+
+        private int elementNesting;
+        private SaxBuffer styling;
+
+        public void setSaxFragment(SaxBuffer saxFragment) {
+            styling = saxFragment;
+        }
+
+        public void recycle() {
+            super.recycle();
+            elementNesting = 0;
+            styling = 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) {
+                styling.toSAX(getContentHandler());
+            }
+            super.endElement(uri, loc, raw);
+        }
+    }
+
+    /**
+     * Inserts validation errors (if any) for the Field widgets
+     */
+    protected class ValidationErrorHandler extends NullHandler {
+        public Handler startElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            setWidget(loc, attrs);
+            return this;
+        }
+
+        public Handler nestedElement(String uri, String loc, String raw, Attributes attrs)
+        throws SAXException {
+            return hNull;
+        }
+
+        public void endElement(String uri, String loc, String raw)
+        throws SAXException {
+            if (widget instanceof ValidationErrorAware) {
+                ValidationError error = ((ValidationErrorAware)widget).getValidationError();
+                if (error != null) {
+                    getContentHandler().startElement(FormsConstants.INSTANCE_NS, VALIDATION_ERROR, FormsConstants.INSTANCE_PREFIX_COLON + VALIDATION_ERROR, XMLUtils.EMPTY_ATTRIBUTES);
+                    error.generateSaxFragment(hStyling);
+                    getContentHandler().endElement(FormsConstants.INSTANCE_NS, VALIDATION_ERROR, FormsConstants.INSTANCE_PREFIX_COLON + VALIDATION_ERROR);
+                }
+            }
+            widget = null;
+        }
+    }
+
+
+
+    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));
+                if(position>-1)
+                    newAtts.setValue(position, newValue);
+                else
+                    throw new RuntimeException("Attribute \""+name+"\" not present!");
+            }
+        }
+        return newAtts;
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/transformation/EffectWidgetReplacingPipe.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message