KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > forms > transformation > EffectWidgetReplacingPipe


1 /*
2  * Copyright 1999-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.forms.transformation;
17
18 import org.apache.avalon.excalibur.pool.Recyclable;
19
20 import org.apache.cocoon.forms.FormsConstants;
21 import org.apache.cocoon.forms.formmodel.AggregateField;
22 import org.apache.cocoon.forms.formmodel.DataWidget;
23 import org.apache.cocoon.forms.formmodel.Group;
24 import org.apache.cocoon.forms.formmodel.Repeater;
25 import org.apache.cocoon.forms.formmodel.Struct;
26 import org.apache.cocoon.forms.formmodel.Union;
27 import org.apache.cocoon.forms.formmodel.Widget;
28 import org.apache.cocoon.forms.validation.ValidationError;
29 import org.apache.cocoon.forms.validation.ValidationErrorAware;
30 import org.apache.cocoon.i18n.I18nUtils;
31 import org.apache.cocoon.xml.AbstractXMLPipe;
32 import org.apache.cocoon.xml.SaxBuffer;
33 import org.apache.cocoon.xml.XMLUtils;
34
35 import org.apache.commons.jxpath.JXPathException;
36 import org.xml.sax.Attributes JavaDoc;
37 import org.xml.sax.ContentHandler JavaDoc;
38 import org.xml.sax.SAXException JavaDoc;
39 import org.xml.sax.ext.LexicalHandler JavaDoc;
40 import org.xml.sax.helpers.AttributesImpl JavaDoc;
41
42 import java.util.ArrayList JavaDoc;
43 import java.util.HashMap JavaDoc;
44 import java.util.LinkedList JavaDoc;
45 import java.util.List JavaDoc;
46 import java.util.Locale JavaDoc;
47 import java.util.Map JavaDoc;
48
49 /**
50  * The basic operation of this Pipe is that it replaces <code>ft:widget</code>
51  * (in the {@link FormsConstants#TEMPLATE_NS} namespace) tags (having an id attribute)
52  * by the XML representation of the corresponding widget instance.
53  *
54  * <p>These XML fragments (normally all in the {@link FormsConstants#INSTANCE_NS "CForms Instance"}
55  * namespace), can then be translated to a HTML presentation by an XSLT.
56  * This XSLT will then only have to style individual widget, and will not
57  * need to do the whole page layout.
58  *
59  * <p>For more information about the supported tags and their function,
60  * see the user documentation for the forms template transformer.</p>
61  *
62  * @version $Id: EffectWidgetReplacingPipe.java 328136 2005-10-24 19:11:48Z sylvain $
63  */

64 public class EffectWidgetReplacingPipe extends EffectPipe {
65
66     /**
67      * Form location attribute on <code>ft:form-template</code> element, containing
68      * JXPath expression which should result in Form object.
69      *
70      * @see FormsPipelineConfig#findForm(String)
71      */

72     private static final String JavaDoc LOCATION = "location";
73
74     private static final String JavaDoc AGGREGATE_WIDGET = "aggregate-widget";
75     private static final String JavaDoc CHOOSE = "choose";
76     private static final String JavaDoc CLASS = "class";
77     private static final String JavaDoc CONTINUATION_ID = "continuation-id";
78     private static final String JavaDoc FORM_TEMPLATE_EL = "form-template";
79     private static final String JavaDoc GROUP = "group";
80     private static final String JavaDoc NEW = "new";
81     private static final String JavaDoc REPEATER = "repeater";
82     private static final String JavaDoc REPEATER_ROWS = "repeater-rows";
83     private static final String JavaDoc REPEATER_SIZE = "repeater-size";
84     private static final String JavaDoc REPEATER_WIDGET = "repeater-widget";
85     private static final String JavaDoc REPEATER_WIDGET_LABEL = "repeater-widget-label";
86     private static final String JavaDoc STRUCT = "struct";
87     private static final String JavaDoc STYLING_EL = "styling";
88     private static final String JavaDoc UNION = "union";
89     private static final String JavaDoc VALIDATION_ERROR = "validation-error";
90     private static final String JavaDoc WIDGET = "widget";
91     private static final String JavaDoc WIDGET_LABEL = "widget-label";
92
93     private final AggregateWidgetHandler hAggregate = new AggregateWidgetHandler();
94     private final ChooseHandler hChoose = new ChooseHandler();
95     private final ChoosePassThruHandler hChoosePassThru = new ChoosePassThruHandler();
96     private final ClassHandler hClass = new ClassHandler();
97     private final ContinuationIdHandler hContinuationId = new ContinuationIdHandler();
98     private final DocHandler hDocument = new DocHandler();
99     private final FormHandler hForm = new FormHandler();
100     private final GroupHandler hGroup = new GroupHandler();
101     private final NestedHandler hNested = new NestedHandler();
102     private final NewHandler hNew = new NewHandler();
103     private final RepeaterSizeHandler hRepeaterSize = new RepeaterSizeHandler();
104     private final RepeaterHandler hRepeater = new RepeaterHandler();
105     private final RepeaterRowsHandler hRepeaterRows = new RepeaterRowsHandler();
106     private final RepeaterWidgetHandler hRepeaterWidget = new RepeaterWidgetHandler();
107     private final RepeaterWidgetLabelHandler hRepeaterWidgetLabel = new RepeaterWidgetLabelHandler();
108     private final SkipHandler hSkip = new SkipHandler();
109     private final StructHandler hStruct = new StructHandler();
110     private final StylingContentHandler hStyling = new StylingContentHandler();
111     private final UnionHandler hUnion = new UnionHandler();
112     private final UnionPassThruHandler hUnionPassThru = new UnionPassThruHandler();
113     private final ValidationErrorHandler hValidationError = new ValidationErrorHandler();
114     private final WidgetHandler hWidget = new WidgetHandler();
115     private final WidgetLabelHandler hWidgetLabel = new WidgetLabelHandler();
116
117     /**
118      * Map containing all handlers
119      */

120     protected final Map JavaDoc templates;
121
122     protected FormsPipelineConfig pipeContext;
123
124     /**
125      * The namespaces and their prefixes
126      */

127     private final List JavaDoc namespaces;
128
129     /**
130      * True if instance namespace has been mapped to the
131      * 'fi' prefix.
132      */

133     private boolean hasInstanceNamespace;
134
135     protected Widget contextWidget;
136     protected LinkedList JavaDoc contextWidgets;
137     protected LinkedList JavaDoc chooseWidgets;
138     protected Widget widget;
139     protected Map JavaDoc classes;
140
141
142     public EffectWidgetReplacingPipe() {
143         namespaces = new ArrayList JavaDoc(5);
144         // Setup map of templates.
145
templates = new HashMap JavaDoc();
146         templates.put(AGGREGATE_WIDGET, hAggregate);
147         templates.put(CHOOSE, hChoose);
148         templates.put(CLASS, hClass);
149         templates.put(CONTINUATION_ID, hContinuationId);
150         templates.put(GROUP, hGroup);
151         templates.put(NEW, hNew);
152         templates.put(REPEATER, hRepeater);
153         templates.put(REPEATER_ROWS, hRepeaterRows);
154         templates.put(REPEATER_SIZE, hRepeaterSize);
155         templates.put(REPEATER_WIDGET, hRepeaterWidget);
156         templates.put(REPEATER_WIDGET_LABEL, hRepeaterWidgetLabel);
157         templates.put(STRUCT, hStruct);
158         templates.put(UNION, hUnion);
159         templates.put(VALIDATION_ERROR, hValidationError);
160         templates.put(WIDGET, hWidget);
161         templates.put(WIDGET_LABEL, hWidgetLabel);
162     }
163
164     public void init(Widget contextWidget, FormsPipelineConfig pipeContext) {
165         // Document handler is top level handler
166
super.init(hDocument);
167         this.pipeContext = pipeContext;
168
169         // Initialize widget related variables
170
this.contextWidgets = new LinkedList JavaDoc();
171         this.chooseWidgets = new LinkedList JavaDoc();
172         this.classes = new HashMap JavaDoc();
173     }
174
175     public void recycle() {
176         super.recycle();
177         this.contextWidget = null;
178         this.widget = null;
179         this.pipeContext = null;
180         this.namespaces.clear();
181         this.hasInstanceNamespace = false;
182     }
183
184     /**
185      * Get value of the required attribute
186      */

187     protected String JavaDoc getAttributeValue(String JavaDoc loc, Attributes JavaDoc attrs, String JavaDoc name) throws SAXException JavaDoc {
188         String JavaDoc value = attrs.getValue(name);
189         if (value == null) {
190             throw new SAXException JavaDoc("Element '" + loc + "' missing required '" + name + "' attribute, " +
191                                    "at " + getLocation());
192         }
193         return value;
194     }
195
196     /**
197      * Get non-empty value of the required attribute
198      */

199     protected String JavaDoc getRequiredAttributeValue(String JavaDoc loc, Attributes JavaDoc attrs, String JavaDoc name) throws SAXException JavaDoc {
200         String JavaDoc value = attrs.getValue(name);
201         if (value == null || value.equals("")) {
202             throw new SAXException JavaDoc("Element '" + loc + "' missing required '" + name + "' attribute, " +
203                                    "at " + getLocation());
204         }
205         return value;
206     }
207
208     /**
209      * Set the widget by the id attribute
210      */

211     protected void setWidget(String JavaDoc loc, Attributes JavaDoc attrs) throws SAXException JavaDoc {
212         setWidget(loc, getRequiredAttributeValue(loc, attrs, "id"));
213     }
214
215     /**
216      * Set the widget by its path
217      */

218     protected void setWidget(String JavaDoc loc, String JavaDoc path) throws SAXException JavaDoc {
219         widget = contextWidget.lookupWidget(path);
220         if (widget == null) {
221             if (contextWidget.getRequestParameterName().equals("")) {
222                 throw new SAXException JavaDoc("Element '" + loc + "' refers to unexistent widget path '" + path + "', " +
223                                        "relative to the form container, at " + getLocation());
224             } else {
225                 throw new SAXException JavaDoc("Element '" + loc + "' refers to unexistent widget path '" + path + "', " +
226                                        "relative to the '" + contextWidget.getRequestParameterName() + "', " +
227                                        "at " + getLocation());
228             }
229         }
230     }
231
232     /**
233      * Set typed widget by the id attribute
234      */

235     protected void setTypedWidget(String JavaDoc loc, Attributes JavaDoc attrs, Class JavaDoc wclass, String JavaDoc wname) throws SAXException JavaDoc {
236         setWidget(loc, attrs);
237         if (!wclass.isInstance(widget)) {
238             throw new SAXException JavaDoc("Element '" + loc + "' can only be used with " + wname + " widgets, " +
239                                    "at " + getLocation());
240         }
241     }
242
243     protected boolean isVisible(Widget widget) {
244         return widget.getCombinedState().isDisplayingValues();
245     }
246
247     /**
248      * Needed to get things working with JDK 1.3. Can be removed once we
249      * don't support that platform any more.
250      */

251     private ContentHandler JavaDoc getContentHandler() {
252         return this.contentHandler;
253     }
254
255     /**
256      * Needed to get things working with JDK 1.3. Can be removed once we
257      * don't support that platform any more.
258      */

259     private LexicalHandler JavaDoc getLexicalHandler() {
260         return this.lexicalHandler;
261     }
262
263
264     /**
265      * Process the SAX event.
266      * @see org.xml.sax.ContentHandler#startPrefixMapping
267      */

268     public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
269     throws SAXException JavaDoc {
270         if (prefix != null) {
271             this.namespaces.add(new String JavaDoc[] {prefix, uri});
272         }
273
274         // Consume template namespace mapping
275
if (!FormsConstants.TEMPLATE_NS.equals(uri)) {
276             super.startPrefixMapping(prefix, uri);
277         }
278     }
279
280     /**
281      * Process the SAX event.
282      * @see org.xml.sax.ContentHandler#endPrefixMapping
283      */

284     public void endPrefixMapping(String JavaDoc prefix)
285     throws SAXException JavaDoc {
286         String JavaDoc uri = null;
287
288         if (prefix != null) {
289             // Find and remove the namespace prefix
290
boolean found = false;
291             for (int i = this.namespaces.size() - 1; i >= 0; i--) {
292                 final String JavaDoc[] prefixAndUri = (String JavaDoc[]) this.namespaces.get(i);
293                 if (prefixAndUri[0].equals(prefix)) {
294                     uri = prefixAndUri[1];
295                     this.namespaces.remove(i);
296                     found = true;
297                     break;
298                 }
299             }
300             if (!found) {
301                 throw new SAXException JavaDoc("Namespace for prefix '" + prefix + "' not found.");
302             }
303         }
304
305         // Consume template namespace mapping
306
if (!FormsConstants.TEMPLATE_NS.equals(uri)) {
307             super.endPrefixMapping(prefix);
308         }
309     }
310
311     /**
312      * @return True if prefix is already mapped into the namespace
313      */

314     protected boolean hasPrefixMapping(String JavaDoc uri, String JavaDoc prefix) {
315         final int l = this.namespaces.size();
316         for (int i = 0; i < l; i++) {
317             String JavaDoc[] prefixAndUri = (String JavaDoc[]) this.namespaces.get(i);
318             if (prefixAndUri[0].equals(prefix) && prefixAndUri[1].equals(uri)) {
319                 return true;
320             }
321         }
322
323         return false;
324     }
325
326     //
327
// Handler classes to transform CForms template elements
328
//
329

330     protected class NestedHandler extends CopyHandler {
331         public Handler JavaDoc nestedElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
332         throws SAXException JavaDoc {
333             // Is it forms namespace?
334
if (!FormsConstants.TEMPLATE_NS.equals(uri)) {
335                 return hNested;
336             }
337
338             Handler JavaDoc handler = (Handler JavaDoc) templates.get(loc);
339             if (handler == null) {
340                 throw new SAXException JavaDoc("Element '" + loc + "' was not recognized, " +
341                                        "at " + getLocation());
342             }
343
344             return handler;
345         }
346     }
347
348     /**
349      * Top level handler for the forms template
350      */

351     protected class DocHandler extends CopyHandler {
352         public Handler JavaDoc nestedElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
353         throws SAXException JavaDoc {
354             if (FormsConstants.TEMPLATE_NS.equals(uri)) {
355                 if (!FORM_TEMPLATE_EL.equals(loc)) {
356                     throw new SAXException JavaDoc("Element '" + loc + "' is not permitted outside of " +
357                                            "'form-template', at " + getLocation());
358                 }
359
360                 return hForm;
361             }
362
363             return super.nestedElement(uri, loc, raw, attrs);
364         }
365     }
366
367     /**
368      * <code>ft:form-template</code> element handler.
369      * <pre>
370      * &lt;ft:form-template locale="..." location="..."&gt;
371      * ...
372      * &lt;/ft:form-template&gt;
373      * </pre>
374      */

375     protected class FormHandler extends NestedHandler {
376         public Handler JavaDoc startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
377         throws SAXException JavaDoc {
378             if (contextWidget != null) {
379                 throw new SAXException JavaDoc("Element 'form-template' can not be nested, " +
380                                        "at " + getLocation());
381             }
382
383             AttributesImpl JavaDoc newAttrs = attrs == null || attrs.getLength() == 0?
384                     new AttributesImpl JavaDoc():
385                     new AttributesImpl JavaDoc(attrs);
386
387             // ====> Retrieve the form
388
String JavaDoc formLocation = attrs.getValue(LOCATION);
389             if (formLocation != null) {
390                 // Remove the location attribute
391
newAttrs.removeAttribute(newAttrs.getIndex(LOCATION));
392             }
393             contextWidget = pipeContext.findForm(formLocation);
394
395             // ====> Check if form visible (and skip it if it's not)
396
if (!isVisible(contextWidget)) {
397                 return hNull;
398             }
399
400             // ====> Determine the Locale
401
// TODO pull this locale stuff also up in the Config object?
402
String JavaDoc localeAttr = attrs.getValue("locale");
403             if (localeAttr != null) { // first use value of locale attribute if any
404
localeAttr = pipeContext.translateText(localeAttr);
405                 pipeContext.setLocale(I18nUtils.parseLocale(localeAttr));
406             } else if (pipeContext.getLocaleParameter() != null) { // then use locale specified as transformer parameter, if any
407
pipeContext.setLocale(pipeContext.getLocaleParameter());
408             } else {
409                 // use locale specified in bizdata supplied for form
410
Object JavaDoc locale = null;
411                 try {
412                     locale = pipeContext.evaluateExpression("/locale");
413                 } catch (JXPathException e) {}
414                 if (locale != null) {
415                     pipeContext.setLocale((Locale JavaDoc)locale);
416                 } else {
417                     // final solution: use locale defined in the server machine
418
pipeContext.setLocale(Locale.getDefault());
419                 }
420             }
421
422             // We need to merge input.attrs with possible overruling attributes
423
// from the pipeContext
424
pipeContext.addFormAttributes(newAttrs);
425             String JavaDoc[] namesToTranslate = {"action"};
426             Attributes JavaDoc transAttrs = null;
427             try {
428                 transAttrs = translateAttributes(newAttrs, namesToTranslate);
429             } catch (RuntimeException JavaDoc e) {
430                 throw new SAXException JavaDoc( e.getMessage() + " " +getLocation());
431             }
432             
433             hasInstanceNamespace = hasPrefixMapping(FormsConstants.INSTANCE_NS, FormsConstants.INSTANCE_PREFIX);
434             if (!hasInstanceNamespace) {
435                 getContentHandler().startPrefixMapping(FormsConstants.INSTANCE_PREFIX, FormsConstants.INSTANCE_NS);
436             }
437             getContentHandler().startElement(FormsConstants.INSTANCE_NS, "form-template", FormsConstants.INSTANCE_PREFIX_COLON + "form-template", transAttrs);
438             return this;
439         }
440
441         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw)
442         throws SAXException JavaDoc {
443             getContentHandler().endElement(FormsConstants.INSTANCE_NS, "form-template", FormsConstants.INSTANCE_PREFIX_COLON + "form-template");
444             if (!hasInstanceNamespace) {
445                 getContentHandler().endPrefixMapping(FormsConstants.INSTANCE_PREFIX);
446             }
447             contextWidget = null;
448         }
449     }
450
451     /**
452      * <code>ft:choose</code>, <code>ft:union</code> use this.
453      */

454     protected class SkipHandler extends NestedHandler {
455         public Handler JavaDoc startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
456         throws SAXException JavaDoc {
457             return this;
458         }
459
460         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw)
461         throws SAXException JavaDoc {
462         }
463     }
464
465     //
466
// Widget Handlers
467
//
468

469     /**
470      * Handles <code>ft:widget-label</code> element.
471      */

472     protected class WidgetLabelHandler extends ErrorHandler {
473         public Handler JavaDoc startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
474         throws SAXException JavaDoc {
475             setWidget(loc, attrs);
476             widget.generateLabel(getContentHandler());
477             return this;
478         }
479
480         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw)
481         throws SAXException JavaDoc {
482         }
483     }
484
485     /**
486      * Handles <code>ft:widget</code> element.
487      */

488     protected class WidgetHandler extends NullHandler {
489         // Widgets can't be nested, so this variable is Ok
490
private boolean hasStyling;
491
492         public Handler JavaDoc startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
493         throws SAXException JavaDoc {
494             setWidget(loc, attrs);
495             if (!isVisible(widget)) {
496                 return hNull;
497             }
498
499             hasStyling = false;
500             return this;
501         }
502
503         public Handler JavaDoc nestedElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
504         throws SAXException JavaDoc {
505             if (FormsConstants.INSTANCE_NS.equals(uri)) {
506                 if (!STYLING_EL.equals(loc)) {
507                     throw new SAXException JavaDoc("Element '" + loc + "' is not permitted within 'widget', " +
508                                            "at " + getLocation());
509                 }
510                 hasStyling = true;
511                 beginBuffer();
512                 // Buffer styling elements
513
return hBuffer;
514             }
515             return hNull;
516         }
517
518         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw)
519         throws SAXException JavaDoc {
520             if (hasStyling) {
521                 // Pipe widget XML through the special handler to insert styling element
522
// before fi:widget end element.
523
hasStyling = false;
524                 hStyling.recycle();
525                 hStyling.setSaxFragment(endBuffer());
526                 hStyling.setContentHandler(getContentHandler());
527                 hStyling.setLexicalHandler(getLexicalHandler());
528                 widget.generateSaxFragment(hStyling, pipeContext.getLocale());
529             } else {
530                 // Pipe widget XML directly into the output handler
531
widget.generateSaxFragment(getContentHandler(), pipeContext.getLocale());
532             }
533             widget = null;
534         }
535     }
536
537     //
538
// Repeater Handlers
539
//
540

541     /**
542      * Handles <code>ft:repeater-size</code> element.
543      */

544     protected class RepeaterSizeHandler extends ErrorHandler {
545         public Handler JavaDoc startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
546         throws SAXException JavaDoc {
547             setTypedWidget(loc, attrs, Repeater.class, "repeater");
548             ((Repeater) widget).generateSize(getContentHandler());
549             widget = null;
550             return this;
551         }
552
553         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw)
554         throws SAXException JavaDoc {
555         }
556     }
557
558     /**
559      * Handles <code>ft:repeater-widget-label</code> element.
560      */

561     protected class RepeaterWidgetLabelHandler extends ErrorHandler {
562         public Handler JavaDoc startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
563         throws SAXException JavaDoc {
564             Repeater repeater;
565             if (contextWidget instanceof Repeater) {
566                 repeater = (Repeater)contextWidget;
567             } else {
568                 setTypedWidget(loc, attrs, Repeater.class, "repeater");
569                 repeater = (Repeater)widget;
570                 widget = null;
571             }
572             String JavaDoc path = getRequiredAttributeValue(loc, attrs, "widget-id");
573             repeater.generateWidgetLabel(path, getContentHandler());
574             return this;
575         }
576
577         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw)
578         throws SAXException JavaDoc {
579         }
580     }
581
582     /**
583      * Handles <code>ft:repeater</code> element. Should contain repeater-rows
584      */

585     protected class RepeaterHandler extends NestedHandler {
586         protected Class JavaDoc getWidgetClass() {
587             return Repeater.class;
588         }
589
590         protected String JavaDoc getWidgetName() {
591             return "repeater";
592         }
593
594         public Handler JavaDoc startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
595         throws SAXException JavaDoc {
596             setTypedWidget(loc, attrs, getWidgetClass(), getWidgetName());
597             if (!isVisible(widget)) {
598                 return hNull;
599             }
600
601             contextWidgets.addFirst(contextWidget);
602             contextWidget = widget;
603             return this;
604         }
605
606         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw)
607         throws SAXException JavaDoc {
608             contextWidget = (Widget) contextWidgets.removeFirst();
609         }
610     }
611
612     /**
613      * Handles <code>ft:repeater-rows</code> element.
614      */

615     protected class RepeaterRowsHandler extends BufferHandler {
616         public Handler JavaDoc startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
617         throws SAXException JavaDoc {
618             if (!(contextWidget instanceof Repeater)) {
619                 throw new SAXException JavaDoc("<repeater-rows> cannot be used with " + contextWidget + ", at " + getLocation());
620             }
621             beginBuffer();
622             return this;
623         }
624
625         public Handler JavaDoc nestedElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
626         throws SAXException JavaDoc {
627             return hBuffer;
628         }
629
630         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw)
631         throws SAXException JavaDoc {
632             SaxBuffer buffer = endBuffer();
633             final Repeater repeater = (Repeater) contextWidget;
634             final int rowCount = repeater.getSize();
635             pushHandler(hNested);
636             contextWidgets.addFirst(contextWidget);
637             for (int i = 0; i < rowCount; i++) {
638                 contextWidget = repeater.getRow(i);
639                 if (isVisible(contextWidget)) {
640                     buffer.toSAX(EffectWidgetReplacingPipe.this);
641                 }
642             }
643             contextWidget = (Widget) contextWidgets.removeFirst();
644             popHandler();
645             widget = null;
646         }
647     }
648
649     /**
650      * Handles <code>ft:repeater-widget</code> element: a single element for both the repeater and its rows
651      */

652     protected class RepeaterWidgetHandler extends BufferHandler {
653         public Handler JavaDoc startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
654         throws SAXException JavaDoc {
655             setTypedWidget(loc, attrs, Repeater.class, "repeater");
656             if (isVisible(widget)) {
657                 beginBuffer();
658                 return this;
659             }
660             return hNull;
661         }
662
663         public Handler JavaDoc nestedElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
664         throws SAXException JavaDoc {
665             return hBuffer;
666         }
667
668         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw)
669         throws SAXException JavaDoc {
670             SaxBuffer buffer = endBuffer();
671             final Repeater repeater = (Repeater) widget;
672             final int rowCount = repeater.getSize();
673             pushHandler(hNested);
674             contextWidgets.addFirst(contextWidget);
675             for (int i = 0; i < rowCount; i++) {
676                 contextWidget = repeater.getRow(i);
677                 if (isVisible(contextWidget)) {
678                     buffer.toSAX(EffectWidgetReplacingPipe.this);
679                 }
680             }
681             contextWidget = (Widget) contextWidgets.removeFirst();
682             popHandler();
683             widget = null;
684         }
685     }
686
687     //
688
// Grouping widgets Handlers
689
//
690

691     /**
692      * Handles <code>ft:group</code> element.
693      */

694     protected class GroupHandler extends NestedHandler {
695         protected Class JavaDoc getWidgetClass() {
696             return Group.class;
697         }
698
699         protected String JavaDoc getWidgetName() {
700             return "group";
701         }
702
703         public Handler JavaDoc startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
704         throws SAXException JavaDoc {
705             setTypedWidget(loc, attrs, getWidgetClass(), getWidgetName());
706             if (!isVisible(widget)) {
707                 return hNull;
708             }
709
710             contextWidgets.addFirst(contextWidget);
711             contextWidget = widget;
712             return this;
713         }
714
715         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw)
716         throws SAXException JavaDoc {
717             contextWidget = (Widget) contextWidgets.removeFirst();
718         }
719     }
720
721     /**
722      * Handles <code>ft:aggregate</code> element.
723      */

724     protected class AggregateWidgetHandler extends GroupHandler {
725         protected Class JavaDoc getWidgetClass() {
726             return AggregateField.class;
727         }
728
729         protected String JavaDoc getWidgetName() {
730             return "aggregate";
731         }
732     }
733
734     /**
735      * Handles <code>ft:choose</code> element.
736      */

737     protected class ChooseHandler extends CopyHandler {
738         public Handler JavaDoc startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs) throws SAXException JavaDoc {
739             setWidget(loc, getRequiredAttributeValue(loc, attrs, "path"));
740             // TODO: Should instead check for datatype convertable to String.
741
if (!(widget instanceof DataWidget)) {
742                 throw new SAXException JavaDoc("Element '" + loc + "' can only be used with DataWidget widgets, " +
743                                        "at " + getLocation());
744             }
745             // Choose does not change the context widget like Union does.
746
chooseWidgets.addFirst(widget);
747             return this;
748         }
749
750         public Handler JavaDoc nestedElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs) throws SAXException JavaDoc {
751             if (FormsConstants.TEMPLATE_NS.equals(uri)) {
752                 if ("when".equals(loc)) {
753                     String JavaDoc testValue = getAttributeValue(loc, attrs, "value");
754                     String JavaDoc value = (String JavaDoc) ((Widget) chooseWidgets.get(0)).getValue();
755                     return testValue.equals(value) ? hSkip : hNull;
756                 }
757                 throw new SAXException JavaDoc("Element '" + loc + "' is not permitted within 'choose', " +
758                                        "at " + getLocation());
759             }
760             return hChoosePassThru;
761         }
762
763         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw) throws SAXException JavaDoc {
764             chooseWidgets.removeFirst();
765         }
766     }
767
768     /**
769      * Handles <code>ft:choose/ft:when</code> element.
770      */

771     protected class ChoosePassThruHandler extends CopyHandler {
772         public Handler JavaDoc nestedElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs) throws SAXException JavaDoc {
773             if (FormsConstants.TEMPLATE_NS.equals(uri)) {
774                 if ("when".equals(loc)) {
775                     String JavaDoc testValue = getAttributeValue(loc, attrs, "value");
776                     String JavaDoc value = (String JavaDoc) ((Widget) chooseWidgets.get(0)).getValue();
777                     return testValue.equals(value)? hSkip: hNull;
778                 }
779                 throw new SAXException JavaDoc("Element '" + loc + "' is not permitted within 'choose', " +
780                                        "at " + getLocation());
781             }
782             return this;
783         }
784     }
785
786     /**
787      * Handles <code>ft:struct</code> element.
788      */

789     protected class StructHandler extends GroupHandler {
790         protected Class JavaDoc getWidgetClass() {
791             return Struct.class;
792         }
793
794         protected String JavaDoc getWidgetName() {
795             return "struct";
796         }
797     }
798
799     /**
800      * Handles <code>ft:union</code> element.
801      */

802     protected class UnionHandler extends GroupHandler {
803         protected Class JavaDoc getWidgetClass() {
804             return Union.class;
805         }
806
807         protected String JavaDoc getWidgetName() {
808             return "union";
809         }
810
811         public Handler JavaDoc nestedElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
812         throws SAXException JavaDoc {
813             if (FormsConstants.TEMPLATE_NS.equals(uri)) {
814                 if ("case".equals(loc)) {
815                     String JavaDoc id = getAttributeValue(loc, attrs, "id");
816                     String JavaDoc value = (String JavaDoc) contextWidget.getValue();
817                     if (id.equals(value != null ? value : "")) {
818                         return hSkip;
819                     }
820                     return hNull;
821                 }
822                 throw new SAXException JavaDoc("Element '" + loc + "' is not permitted within 'union', " +
823                                        "at " + getLocation());
824             }
825             return hUnionPassThru;
826         }
827     }
828
829     /**
830      * Handles <code>ft:union/ft:case</code> element.
831      */

832     protected class UnionPassThruHandler extends CopyHandler {
833         public Handler JavaDoc nestedElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
834         throws SAXException JavaDoc {
835             if (FormsConstants.TEMPLATE_NS.equals(uri)) {
836                 if ("case".equals(loc)) {
837                     if (contextWidget.getValue().equals(attrs.getValue("id"))) {
838                         return hSkip;
839                     }
840                     return hNull;
841                 }
842                 throw new SAXException JavaDoc("Element '" + loc + "' is not permitted within 'union', " +
843                                        "at " + getLocation());
844             }
845             return this;
846         }
847     }
848
849     /**
850      * Handles <code>ft:new</code> element.
851      */

852     protected class NewHandler extends CopyHandler {
853         public Handler JavaDoc startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
854         throws SAXException JavaDoc {
855             String JavaDoc id = getRequiredAttributeValue(loc, attrs, "id");
856             SaxBuffer buffer = (SaxBuffer) classes.get(id);
857             if (buffer == null) {
858                 throw new SAXException JavaDoc("New: Class '" + id + "' does not exist, " +
859                                        "at " + getLocation());
860             }
861             pushHandler(hNested);
862             buffer.toSAX(EffectWidgetReplacingPipe.this);
863             popHandler();
864             return this;
865         }
866
867         public Handler JavaDoc nestedElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
868         throws SAXException JavaDoc {
869             return hNull;
870         }
871
872         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw)
873         throws SAXException JavaDoc {
874         }
875     }
876
877     /**
878      * Handles <code>ft:class</code> element.
879      * <pre>
880      * &lt;ft:class id="..."&gt;
881      * ...
882      * &lt;/ft:class&gt;
883      * </pre>
884      */

885     protected class ClassHandler extends BufferHandler {
886         // FIXME What if <class> is nested within <class>?
887
private String JavaDoc widgetPath;
888
889         public Handler JavaDoc startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
890         throws SAXException JavaDoc {
891             widgetPath = getRequiredAttributeValue(loc, attrs, "id");
892             beginBuffer();
893             return this;
894         }
895
896         public Handler JavaDoc nestedElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
897         throws SAXException JavaDoc {
898             return hBuffer;
899         }
900
901         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw) throws SAXException JavaDoc {
902             classes.put(widgetPath, endBuffer());
903         }
904     }
905
906     /**
907      * Handles <code>ft:continuation-id</code> element.
908      * <pre>
909      * &lt;ft:continuation-id/&gt;
910      * </pre>
911      */

912     protected class ContinuationIdHandler extends ErrorHandler {
913         protected String JavaDoc getName() {
914             return "continuation-id";
915         }
916
917         public Handler JavaDoc startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
918         throws SAXException JavaDoc {
919             // Insert the continuation id
920
// FIXME(SW) we could avoid costly JXPath evaluation if we had the objectmodel here.
921
Object JavaDoc idObj = pipeContext.evaluateExpression("$cocoon/continuation/id");
922             if (idObj == null) {
923                 throw new SAXException JavaDoc("No continuation found");
924             }
925
926             String JavaDoc id = idObj.toString();
927             getContentHandler().startElement(FormsConstants.INSTANCE_NS, "continuation-id", FormsConstants.INSTANCE_PREFIX_COLON + "continuation-id", attrs);
928             getContentHandler().characters(id.toCharArray(), 0, id.length());
929             getContentHandler().endElement(FormsConstants.INSTANCE_NS, "continuation-id", FormsConstants.INSTANCE_PREFIX_COLON + "continuation-id");
930             return this;
931         }
932
933         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw) throws SAXException JavaDoc {
934         }
935     }
936
937     /**
938      * This ContentHandler helps in inserting SAX events before the closing tag of the root
939      * element.
940      */

941     protected class StylingContentHandler extends AbstractXMLPipe
942                                           implements Recyclable {
943
944         private int elementNesting;
945         private SaxBuffer styling;
946
947         public void setSaxFragment(SaxBuffer saxFragment) {
948             styling = saxFragment;
949         }
950
951         public void recycle() {
952             super.recycle();
953             elementNesting = 0;
954             styling = null;
955         }
956
957         public void startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc a)
958         throws SAXException JavaDoc {
959             elementNesting++;
960             super.startElement(uri, loc, raw, a);
961         }
962
963         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw)
964         throws SAXException JavaDoc {
965             elementNesting--;
966             if (elementNesting == 0) {
967                 styling.toSAX(getContentHandler());
968             }
969             super.endElement(uri, loc, raw);
970         }
971     }
972
973     /**
974      * Inserts validation errors (if any) for the Field widgets
975      */

976     protected class ValidationErrorHandler extends NullHandler {
977         public Handler JavaDoc startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
978         throws SAXException JavaDoc {
979             setWidget(loc, attrs);
980             return this;
981         }
982
983         public Handler JavaDoc nestedElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc attrs)
984         throws SAXException JavaDoc {
985             return hNull;
986         }
987
988         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw)
989         throws SAXException JavaDoc {
990             if (widget instanceof ValidationErrorAware) {
991                 ValidationError error = ((ValidationErrorAware)widget).getValidationError();
992                 if (error != null) {
993                     getContentHandler().startElement(FormsConstants.INSTANCE_NS, VALIDATION_ERROR, FormsConstants.INSTANCE_PREFIX_COLON + VALIDATION_ERROR, XMLUtils.EMPTY_ATTRIBUTES);
994                     error.generateSaxFragment(hStyling);
995                     getContentHandler().endElement(FormsConstants.INSTANCE_NS, VALIDATION_ERROR, FormsConstants.INSTANCE_PREFIX_COLON + VALIDATION_ERROR);
996                 }
997             }
998             widget = null;
999         }
1000    }
1001
1002
1003
1004    private Attributes JavaDoc translateAttributes(Attributes JavaDoc attributes, String JavaDoc[] names) {
1005        AttributesImpl JavaDoc newAtts = new AttributesImpl JavaDoc(attributes);
1006        if (names!= null) {
1007            for (int i = 0; i < names.length; i++) {
1008                String JavaDoc name = names[i];
1009                int position = newAtts.getIndex(name);
1010                String JavaDoc newValue = pipeContext.translateText(newAtts.getValue(position));
1011                if(position>-1)
1012                    newAtts.setValue(position, newValue);
1013                else
1014                    throw new RuntimeException JavaDoc("Attribute \""+name+"\" not present!");
1015            }
1016        }
1017        return newAtts;
1018    }
1019}
1020
Popular Tags