KickJava   Java API By Example, From Geeks To Geeks.

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

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

63     protected boolean inWidgetElement;
64
65     /**
66      * Buffer used to temporarily record SAX events.
67      */

68     protected SaxBuffer saxBuffer;
69
70     /**
71      * Counts the element nesting.
72      */

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

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

85     protected Widget widget;
86
87     /**
88      * Boolean indicating wether the current widget requires special repeater-treatement.
89      */

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

98     protected boolean gotStylingElement;
99
100     /**
101      * Namespace prefix used for the namespace <code>Constants.WT_NS</code>.
102      */

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

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

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

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