KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Copyright 1999-2004 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 java.util.Locale JavaDoc;
19
20 import org.apache.avalon.excalibur.pool.Recyclable;
21 import org.apache.cocoon.forms.Constants;
22 import org.apache.cocoon.forms.formmodel.ContainerWidget;
23 import org.apache.cocoon.forms.formmodel.Repeater;
24 import org.apache.cocoon.forms.formmodel.Widget;
25 import org.apache.cocoon.i18n.I18nUtils;
26 import org.apache.cocoon.xml.AbstractXMLPipe;
27 import org.apache.cocoon.xml.SaxBuffer;
28 import org.apache.cocoon.xml.XMLUtils;
29 import org.apache.commons.jxpath.JXPathException;
30 import org.xml.sax.Attributes JavaDoc;
31 import org.xml.sax.SAXException JavaDoc;
32 import org.xml.sax.helpers.AttributesImpl JavaDoc;
33
34 /**
35  * The basic operation of this Pipe is that it replaces wt:widget (in the
36  * {@link Constants#TEMPLATE_NS} namespace) tags (having an id attribute)
37  * by the XML representation of the corresponding widget instance.
38  *
39  * <p>These XML fragments (normally all in the
40  * {@link Constants#INSTANCE_NS "Cocoon Forms Instance"} namespace), can then be
41  * translated to a HTML presentation by an XSL. This XSL will then only have to
42  * style individual widget, and will not need to do the whole page layout.
43  *
44  * <p>For more information about the supported tags and their function, see the user documentation
45  * for the forms template transformer.</p>
46  *
47  * @version $Id: WidgetReplacingPipe.java 151181 2005-02-03 16:59:31Z tim $
48  */

49 public class WidgetReplacingPipe extends AbstractXMLPipe {
50
51     private static final String JavaDoc REPEATER_SIZE = "repeater-size";
52     private static final String JavaDoc REPEATER_WIDGET_LABEL = "repeater-widget-label";
53     private static final String JavaDoc WIDGET_LABEL = "widget-label";
54     private static final String JavaDoc WIDGET = "widget";
55     private static final String JavaDoc LOCATION = "location";
56     private static final String JavaDoc REPEATER_WIDGET = "repeater-widget";
57     private static final String JavaDoc CONTINUATION_ID = "continuation-id";
58     private static final String JavaDoc FORM_TEMPLATE_EL = "form-template";
59     private static final String JavaDoc STYLING_EL = "styling";
60
61     protected Widget contextWidget;
62
63     /**
64      * Indicates whether we're currently in a widget element.
65      */

66     protected boolean inWidgetElement;
67
68     /**
69      * Buffer used to temporarily record SAX events.
70      */

71     protected SaxBuffer saxBuffer;
72
73     /**
74      * Counts the element nesting.
75      */

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

83     protected int widgetElementNesting;
84
85     /**
86      * If {@link #inWidgetElement} = true, then this contains the widget currenlty being handled.
87      */

88     protected Widget widget;
89
90     /**
91      * Boolean indicating wether the current widget requires special repeater-treatement.
92      */

93     protected boolean repeaterWidget;
94
95     protected WidgetReplacingPipe.InsertStylingContentHandler stylingHandler = new WidgetReplacingPipe.InsertStylingContentHandler();
96     protected FormsPipelineConfig pipeContext;
97
98     /**
99      * Have we encountered a <wi:style> element in a widget ?
100      */

101     protected boolean gotStylingElement;
102
103     /**
104      * Namespace prefix used for the namespace <code>Constants.FT_NS</code>.
105      */

106     protected String JavaDoc namespacePrefix;
107     
108
109     public void init(Widget newContextWidget, FormsPipelineConfig newPipeContext) {
110         contextWidget = newContextWidget;
111         inWidgetElement = false;
112         elementNestingCounter = 0;
113         pipeContext = newPipeContext;
114     }
115
116     public void startElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName, Attributes JavaDoc attributes)
117             throws SAXException JavaDoc {
118         elementNestingCounter++;
119
120         if (inWidgetElement) {
121             if (elementNestingCounter == widgetElementNesting + 1 &&
122                 Constants.INSTANCE_NS.equals(namespaceURI) && STYLING_EL.equals(localName)) {
123                 gotStylingElement = true;
124             }
125             saxBuffer.startElement(namespaceURI, localName, qName, attributes);
126         } else if (Constants.TEMPLATE_NS.equals(namespaceURI)) {
127             if (localName.equals(WIDGET) || localName.equals(REPEATER_WIDGET)) {
128                 checkContextWidgetAvailable(qName);
129                 inWidgetElement = true;
130                 widgetElementNesting = elementNestingCounter;
131                 gotStylingElement = false;
132                 saxBuffer = new SaxBuffer();
133                 // retrieve widget here, but its XML will only be streamed in the endElement call
134
widget = getWidget(attributes);
135                 repeaterWidget = localName.equals(REPEATER_WIDGET);
136                 if (repeaterWidget && !(widget instanceof Repeater)) {
137                     throw new SAXException JavaDoc("FormsTemplateTransformer: the element \"repeater-widget\" can only be used for repeater widgets.");
138                 }
139             } else if (localName.equals(WIDGET_LABEL)) {
140                 checkContextWidgetAvailable(qName);
141                 Widget widget = getWidget(attributes);
142                 widget.generateLabel(contentHandler);
143             } else if (localName.equals(REPEATER_WIDGET_LABEL)) {
144                 checkContextWidgetAvailable(qName);
145                 Widget widget = getWidget(attributes);
146                 if (!(widget instanceof Repeater)) {
147                     throw new SAXException JavaDoc("FormsTemplateTransformer: the element \"repeater-widget-label\" can only be used for repeater widgets.");
148                 }
149                 String JavaDoc widgetId = attributes.getValue("widget-id");
150                 if (widgetId == null || widgetId.equals("")) {
151                     throw new SAXException JavaDoc("FormsTemplateTransformer: the element \"repeater-widget-label\" requires a \"widget-id\" attribute.");
152                 }
153                 ((Repeater)widget).generateWidgetLabel(widgetId, contentHandler);
154             } else if (localName.equals(REPEATER_SIZE)) {
155                 checkContextWidgetAvailable(qName);
156                 Widget widget = getWidget(attributes);
157                 if (!(widget instanceof Repeater))
158                     throw new SAXException JavaDoc("FormsTemplateTransformer: the element \"repeater-size\" can only be used for repeater widgets.");
159                 contentHandler.startPrefixMapping(Constants.INSTANCE_PREFIX, Constants.INSTANCE_NS);
160                 ((Repeater)widget).generateSize(contentHandler);
161                 contentHandler.endPrefixMapping(Constants.INSTANCE_PREFIX);
162             } else if (localName.equals(FORM_TEMPLATE_EL)) {
163                 if (contextWidget != null) {
164                     throw new SAXException JavaDoc("Detected nested ft:form-template elements, this is not allowed.");
165                 }
166                 contentHandler.startPrefixMapping(Constants.INSTANCE_PREFIX, Constants.INSTANCE_NS);
167
168                 // ====> Retrieve the form
169

170                 // first look for the form using the location attribute, if any
171
String JavaDoc formJXPath = attributes.getValue(LOCATION);
172                 if (formJXPath != null) {
173                     // remove the location attribute
174
AttributesImpl JavaDoc attrsCopy = new AttributesImpl JavaDoc(attributes);
175                     attrsCopy.removeAttribute(attributes.getIndex(LOCATION));
176                     attributes = attrsCopy;
177                 }
178                 contextWidget = pipeContext.findForm(formJXPath);
179
180                 // ====> Determine the Locale
181
//TODO pull this locale stuff also up in the Config object?
182

183                 String JavaDoc localeAttr = attributes.getValue("locale");
184                 if (localeAttr != null) { // first use value of locale attribute if any
185
localeAttr = pipeContext.translateText(localeAttr);
186                     pipeContext.setLocale(I18nUtils.parseLocale(localeAttr));
187                 } else if (pipeContext.getLocaleParameter() != null) { // then use locale specified as transformer parameter, if any
188
pipeContext.setLocale(pipeContext.getLocaleParameter());
189                 } else { // use locale specified in bizdata supplied for form
190
Object JavaDoc locale = null;
191                     try {
192                         locale = pipeContext.evaluateExpression("/locale");
193                     } catch (JXPathException e) {}
194                     if (locale != null) {
195                         pipeContext.setLocale((Locale JavaDoc)locale);
196                     }
197                     else {
198                         // final solution: use locale defined in the server machine
199
pipeContext.setLocale(Locale.getDefault());
200                     }
201                 }
202
203                 String JavaDoc[] namesToTranslate = {"action"};
204                 Attributes JavaDoc transAtts = translateAttributes(attributes, namesToTranslate);
205                 contentHandler.startElement(Constants.INSTANCE_NS , FORM_TEMPLATE_EL, Constants.INSTANCE_PREFIX_COLON + FORM_TEMPLATE_EL, transAtts);
206
207             } else if (localName.equals(CONTINUATION_ID)){
208                 // Insert the continuation id
209
// FIXME(SW) we could avoid costly JXPath evaluation if we had the objectmodel here.
210
Object JavaDoc idObj = pipeContext.evaluateExpression("$continuation/id");
211                 if (idObj == null) {
212                     throw new SAXException JavaDoc("No continuation found");
213                 }
214
215                 String JavaDoc id = idObj.toString();
216                 contentHandler.startPrefixMapping(Constants.INSTANCE_PREFIX, Constants.INSTANCE_NS);
217                 contentHandler.startElement(Constants.INSTANCE_NS, CONTINUATION_ID, Constants.INSTANCE_PREFIX_COLON + CONTINUATION_ID, attributes);
218                 contentHandler.characters(id.toCharArray(), 0, id.length());
219                 contentHandler.endElement(Constants.INSTANCE_NS, CONTINUATION_ID, Constants.INSTANCE_PREFIX_COLON + CONTINUATION_ID);
220                 contentHandler.endPrefixMapping(Constants.INSTANCE_PREFIX);
221             } else {
222                 throw new SAXException JavaDoc("FormsTemplateTransformer: Unsupported element: " + localName);
223             }
224         } else {
225             super.startElement(namespaceURI, localName, qName, attributes);
226         }
227     }
228
229     private void checkContextWidgetAvailable(String JavaDoc widgetElementName) throws SAXException JavaDoc {
230         if (contextWidget == null)
231             throw new SAXException JavaDoc(widgetElementName + " cannot be used outside a wt:form-template element");
232     }
233
234     private Attributes JavaDoc translateAttributes(Attributes JavaDoc attributes, String JavaDoc[] names) {
235         AttributesImpl JavaDoc newAtts = new AttributesImpl JavaDoc(attributes);
236         if (names!= null) {
237             for (int i = 0; i < names.length; i++) {
238                 String JavaDoc name = names[i];
239                 int position = newAtts.getIndex(name);
240                 String JavaDoc newValue = pipeContext.translateText(newAtts.getValue(position));
241                 newAtts.setValue(position, newValue);
242             }
243         }
244         return newAtts;
245     }
246
247
248     protected Widget getWidget(Attributes JavaDoc attributes) throws SAXException JavaDoc {
249         String JavaDoc widgetId = attributes.getValue("id");
250         if (widgetId == null || widgetId.equals("")) {
251             throw new SAXException JavaDoc("FormsTemplateTransformer: missing id attribute on a Cocoon Forms element.");
252         }
253         Widget widget = ((ContainerWidget)contextWidget).getChild(widgetId);
254         if (widget == null) {
255             throw new SAXException JavaDoc("FormsTemplateTransformer: widget with id \"" + widgetId + "\" does not exist in the container " + contextWidget.getRequestParameterName());
256         }
257         return widget;
258     }
259
260     public void endElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName)
261             throws SAXException JavaDoc {
262
263         if (inWidgetElement) {
264             if (elementNestingCounter == widgetElementNesting && Constants.TEMPLATE_NS.equals(namespaceURI)
265                 && (localName.equals(WIDGET) || localName.equals(REPEATER_WIDGET))) {
266                     if (repeaterWidget) {
267                         Repeater repeater = (Repeater)widget;
268                         WidgetReplacingPipe rowPipe = new WidgetReplacingPipe();
269                         int rowCount = repeater.getSize();
270                         for (int i = 0; i < rowCount; i++) {
271                             Repeater.RepeaterRow row = repeater.getRow(i);
272                             rowPipe.init(row, pipeContext);
273                             rowPipe.setContentHandler(contentHandler);
274                             rowPipe.setLexicalHandler(lexicalHandler);
275                             saxBuffer.toSAX(rowPipe);
276                             rowPipe.recycle();
277                         }
278                     } else {
279                         stylingHandler.recycle();
280                         stylingHandler.setSaxFragment(saxBuffer);
281                         stylingHandler.setContentHandler(contentHandler);
282                         stylingHandler.setLexicalHandler(lexicalHandler);
283                         contentHandler.startPrefixMapping(Constants.INSTANCE_PREFIX, Constants.INSTANCE_NS);
284                         widget.generateSaxFragment(stylingHandler, pipeContext.getLocale());
285                         contentHandler.endPrefixMapping(Constants.INSTANCE_PREFIX);
286                     }
287                     inWidgetElement = false;
288                     widget = null;
289                 } else {
290                     saxBuffer.endElement(namespaceURI, localName, qName);
291                 }
292         } else if (Constants.TEMPLATE_NS.equals(namespaceURI)) {
293             if (localName.equals(WIDGET_LABEL) || localName.equals(REPEATER_WIDGET_LABEL)
294                 || localName.equals(REPEATER_SIZE) || localName.equals(CONTINUATION_ID)) {
295                 // Do nothing
296
} else if (localName.equals(FORM_TEMPLATE_EL)) {
297                 contextWidget = null;
298                 contentHandler.endElement(Constants.INSTANCE_NS, FORM_TEMPLATE_EL,
299                                           Constants.INSTANCE_PREFIX_COLON + FORM_TEMPLATE_EL);
300                 contentHandler.endPrefixMapping(Constants.INSTANCE_PREFIX);
301             } else {
302                 super.endElement(namespaceURI, localName, qName);
303             }
304         } else {
305             super.endElement(namespaceURI, localName, qName);
306         }
307         elementNestingCounter--;
308     }
309
310     public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
311             throws SAXException JavaDoc {
312         if (inWidgetElement) {
313             saxBuffer.startPrefixMapping(prefix, uri);
314         } else {
315             super.startPrefixMapping(prefix, uri);
316         }
317     }
318
319     public void endPrefixMapping(String JavaDoc prefix)
320             throws SAXException JavaDoc {
321         if (inWidgetElement) {
322             saxBuffer.endPrefixMapping(prefix);
323         } else {
324             super.endPrefixMapping(prefix);
325         }
326     }
327
328     public void characters(char c[], int start, int len)
329             throws SAXException JavaDoc {
330         if (inWidgetElement) {
331             saxBuffer.characters(c, start, len);
332         } else {
333             super.characters(c, start, len);
334         }
335     }
336
337     public void ignorableWhitespace(char c[], int start, int len)
338             throws SAXException JavaDoc {
339         if (inWidgetElement) {
340             saxBuffer.ignorableWhitespace(c, start, len);
341         } else {
342             super.ignorableWhitespace(c, start, len);
343         }
344     }
345
346     public void processingInstruction(String JavaDoc target, String JavaDoc data)
347             throws SAXException JavaDoc {
348         if (inWidgetElement) {
349             saxBuffer.processingInstruction(target, data);
350         } else {
351             super.processingInstruction(target, data);
352         }
353     }
354
355     public void skippedEntity(String JavaDoc name)
356             throws SAXException JavaDoc {
357         if (inWidgetElement) {
358             saxBuffer.skippedEntity(name);
359         } else {
360             super.skippedEntity(name);
361         }
362     }
363
364     public void startEntity(String JavaDoc name)
365             throws SAXException JavaDoc {
366         if (inWidgetElement)
367             saxBuffer.startEntity(name);
368         else
369             super.startEntity(name);
370     }
371
372     public void endEntity(String JavaDoc name)
373             throws SAXException JavaDoc {
374         if (inWidgetElement) {
375             saxBuffer.endEntity(name);
376         } else {
377             super.endEntity(name);
378         }
379     }
380
381     public void startCDATA()
382             throws SAXException JavaDoc {
383         if (inWidgetElement) {
384             saxBuffer.startCDATA();
385         } else {
386             super.startCDATA();
387         }
388     }
389
390     public void endCDATA()
391             throws SAXException JavaDoc {
392         if (inWidgetElement) {
393             saxBuffer.endCDATA();
394         } else {
395             super.endCDATA();
396         }
397     }
398
399     public void comment(char ch[], int start, int len)
400             throws SAXException JavaDoc {
401         if (inWidgetElement) {
402             saxBuffer.comment(ch, start, len);
403         } else {
404             super.comment(ch, start, len);
405         }
406     }
407
408     public void recycle() {
409         super.recycle();
410         this.contextWidget = null;
411         this.widget = null;
412         this.namespacePrefix = null;
413     }
414
415     /**
416      * This ContentHandler helps in inserting SAX events before the closing tag of the root
417      * element.
418      */

419     public class InsertStylingContentHandler extends AbstractXMLPipe implements Recyclable {
420         private int elementNesting;
421         private SaxBuffer saxBuffer;
422
423         public void setSaxFragment(SaxBuffer saxFragment) {
424             saxBuffer = saxFragment;
425         }
426
427         public void recycle() {
428             super.recycle();
429             elementNesting = 0;
430             saxBuffer = null;
431         }
432
433         public void startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc a)
434                 throws SAXException JavaDoc {
435             elementNesting++;
436             super.startElement(uri, loc, raw, a);
437         }
438
439         public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw)
440                 throws SAXException JavaDoc {
441             elementNesting--;
442             if (elementNesting == 0 && saxBuffer != null) {
443                 if (gotStylingElement) {
444                     // Just deserialize
445
saxBuffer.toSAX(contentHandler);
446                 } else {
447                     // Insert an enclosing <wi:styling>
448
contentHandler.startElement(Constants.INSTANCE_NS, STYLING_EL, Constants.INSTANCE_PREFIX_COLON + STYLING_EL, XMLUtils.EMPTY_ATTRIBUTES);
449                     saxBuffer.toSAX(contentHandler);
450                     contentHandler.endElement(Constants.INSTANCE_NS, STYLING_EL, Constants.INSTANCE_PREFIX_COLON + STYLING_EL);
451                 }
452             }
453             super.endElement(uri, loc, raw);
454         }
455     }
456 }
457
Popular Tags