1 16 package org.apache.cocoon.forms.transformation; 17 18 import java.util.Locale ; 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 ; 31 import org.xml.sax.SAXException ; 32 import org.xml.sax.helpers.AttributesImpl ; 33 34 49 public class WidgetReplacingPipe extends AbstractXMLPipe { 50 51 private static final String REPEATER_SIZE = "repeater-size"; 52 private static final String REPEATER_WIDGET_LABEL = "repeater-widget-label"; 53 private static final String WIDGET_LABEL = "widget-label"; 54 private static final String WIDGET = "widget"; 55 private static final String LOCATION = "location"; 56 private static final String REPEATER_WIDGET = "repeater-widget"; 57 private static final String CONTINUATION_ID = "continuation-id"; 58 private static final String FORM_TEMPLATE_EL = "form-template"; 59 private static final String STYLING_EL = "styling"; 60 61 protected Widget contextWidget; 62 63 66 protected boolean inWidgetElement; 67 68 71 protected SaxBuffer saxBuffer; 72 73 76 protected int elementNestingCounter; 77 78 83 protected int widgetElementNesting; 84 85 88 protected Widget widget; 89 90 93 protected boolean repeaterWidget; 94 95 protected WidgetReplacingPipe.InsertStylingContentHandler stylingHandler = new WidgetReplacingPipe.InsertStylingContentHandler(); 96 protected FormsPipelineConfig pipeContext; 97 98 101 protected boolean gotStylingElement; 102 103 106 protected String 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 namespaceURI, String localName, String qName, Attributes attributes) 117 throws SAXException { 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 widget = getWidget(attributes); 135 repeaterWidget = localName.equals(REPEATER_WIDGET); 136 if (repeaterWidget && !(widget instanceof Repeater)) { 137 throw new SAXException ("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 ("FormsTemplateTransformer: the element \"repeater-widget-label\" can only be used for repeater widgets."); 148 } 149 String widgetId = attributes.getValue("widget-id"); 150 if (widgetId == null || widgetId.equals("")) { 151 throw new SAXException ("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 ("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 ("Detected nested ft:form-template elements, this is not allowed."); 165 } 166 contentHandler.startPrefixMapping(Constants.INSTANCE_PREFIX, Constants.INSTANCE_NS); 167 168 170 String formJXPath = attributes.getValue(LOCATION); 172 if (formJXPath != null) { 173 AttributesImpl attrsCopy = new AttributesImpl (attributes); 175 attrsCopy.removeAttribute(attributes.getIndex(LOCATION)); 176 attributes = attrsCopy; 177 } 178 contextWidget = pipeContext.findForm(formJXPath); 179 180 183 String localeAttr = attributes.getValue("locale"); 184 if (localeAttr != null) { localeAttr = pipeContext.translateText(localeAttr); 186 pipeContext.setLocale(I18nUtils.parseLocale(localeAttr)); 187 } else if (pipeContext.getLocaleParameter() != null) { pipeContext.setLocale(pipeContext.getLocaleParameter()); 189 } else { Object locale = null; 191 try { 192 locale = pipeContext.evaluateExpression("/locale"); 193 } catch (JXPathException e) {} 194 if (locale != null) { 195 pipeContext.setLocale((Locale )locale); 196 } 197 else { 198 pipeContext.setLocale(Locale.getDefault()); 200 } 201 } 202 203 String [] namesToTranslate = {"action"}; 204 Attributes 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 Object idObj = pipeContext.evaluateExpression("$continuation/id"); 211 if (idObj == null) { 212 throw new SAXException ("No continuation found"); 213 } 214 215 String 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 ("FormsTemplateTransformer: Unsupported element: " + localName); 223 } 224 } else { 225 super.startElement(namespaceURI, localName, qName, attributes); 226 } 227 } 228 229 private void checkContextWidgetAvailable(String widgetElementName) throws SAXException { 230 if (contextWidget == null) 231 throw new SAXException (widgetElementName + " cannot be used outside a wt:form-template element"); 232 } 233 234 private Attributes translateAttributes(Attributes attributes, String [] names) { 235 AttributesImpl newAtts = new AttributesImpl (attributes); 236 if (names!= null) { 237 for (int i = 0; i < names.length; i++) { 238 String name = names[i]; 239 int position = newAtts.getIndex(name); 240 String newValue = pipeContext.translateText(newAtts.getValue(position)); 241 newAtts.setValue(position, newValue); 242 } 243 } 244 return newAtts; 245 } 246 247 248 protected Widget getWidget(Attributes attributes) throws SAXException { 249 String widgetId = attributes.getValue("id"); 250 if (widgetId == null || widgetId.equals("")) { 251 throw new SAXException ("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 ("FormsTemplateTransformer: widget with id \"" + widgetId + "\" does not exist in the container " + contextWidget.getRequestParameterName()); 256 } 257 return widget; 258 } 259 260 public void endElement(String namespaceURI, String localName, String qName) 261 throws SAXException { 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 } 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 prefix, String uri) 311 throws SAXException { 312 if (inWidgetElement) { 313 saxBuffer.startPrefixMapping(prefix, uri); 314 } else { 315 super.startPrefixMapping(prefix, uri); 316 } 317 } 318 319 public void endPrefixMapping(String prefix) 320 throws SAXException { 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 { 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 { 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 target, String data) 347 throws SAXException { 348 if (inWidgetElement) { 349 saxBuffer.processingInstruction(target, data); 350 } else { 351 super.processingInstruction(target, data); 352 } 353 } 354 355 public void skippedEntity(String name) 356 throws SAXException { 357 if (inWidgetElement) { 358 saxBuffer.skippedEntity(name); 359 } else { 360 super.skippedEntity(name); 361 } 362 } 363 364 public void startEntity(String name) 365 throws SAXException { 366 if (inWidgetElement) 367 saxBuffer.startEntity(name); 368 else 369 super.startEntity(name); 370 } 371 372 public void endEntity(String name) 373 throws SAXException { 374 if (inWidgetElement) { 375 saxBuffer.endEntity(name); 376 } else { 377 super.endEntity(name); 378 } 379 } 380 381 public void startCDATA() 382 throws SAXException { 383 if (inWidgetElement) { 384 saxBuffer.startCDATA(); 385 } else { 386 super.startCDATA(); 387 } 388 } 389 390 public void endCDATA() 391 throws SAXException { 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 { 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 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 uri, String loc, String raw, Attributes a) 434 throws SAXException { 435 elementNesting++; 436 super.startElement(uri, loc, raw, a); 437 } 438 439 public void endElement(String uri, String loc, String raw) 440 throws SAXException { 441 elementNesting--; 442 if (elementNesting == 0 && saxBuffer != null) { 443 if (gotStylingElement) { 444 saxBuffer.toSAX(contentHandler); 446 } else { 447 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 |