1 16 package org.apache.cocoon.woody.transformation; 17 18 import java.util.Locale ; 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 ; 29 import org.xml.sax.SAXException ; 30 import org.xml.sax.helpers.AttributesImpl ; 31 32 46 public class WidgetReplacingPipe extends AbstractXMLPipe { 47 48 private static final String REPEATER_SIZE = "repeater-size"; 49 private static final String REPEATER_WIDGET_LABEL = "repeater-widget-label"; 50 private static final String WIDGET_LABEL = "widget-label"; 51 private static final String WIDGET = "widget"; 52 private static final String LOCATION = "location"; 53 private static final String REPEATER_WIDGET = "repeater-widget"; 54 private static final String CONTINUATION_ID = "continuation-id"; 55 private static final String FORM_TEMPLATE_EL = "form-template"; 56 private static final String STYLING_EL = "styling"; 57 58 protected Widget contextWidget; 59 60 63 protected boolean inWidgetElement; 64 65 68 protected SaxBuffer saxBuffer; 69 70 73 protected int elementNestingCounter; 74 75 80 protected int widgetElementNesting; 81 82 85 protected Widget widget; 86 87 90 protected boolean repeaterWidget; 91 92 protected WidgetReplacingPipe.InsertStylingContentHandler stylingHandler = new WidgetReplacingPipe.InsertStylingContentHandler(); 93 protected WoodyPipelineConfig pipeContext; 94 95 98 protected boolean gotStylingElement; 99 100 103 protected String 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 namespaceURI, String localName, String qName, Attributes attributes) 114 throws SAXException { 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 widget = getWidget(attributes); 132 repeaterWidget = localName.equals(REPEATER_WIDGET); 133 if (repeaterWidget && !(widget instanceof Repeater)) { 134 throw new SAXException ("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 ("WoodyTemplateTransformer: the element \"repeater-widget-label\" can only be used for repeater widgets."); 145 } 146 String widgetId = attributes.getValue("widget-id"); 147 if (widgetId == null || widgetId.equals("")) { 148 throw new SAXException ("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 ("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 ("Detected nested wt:form-template elements, this is not allowed."); 162 } 163 contentHandler.startPrefixMapping(Constants.WI_PREFIX, Constants.WI_NS); 164 165 167 String formJXPath = attributes.getValue(LOCATION); 169 if (formJXPath != null) { 170 AttributesImpl attrsCopy = new AttributesImpl (attributes); 172 attrsCopy.removeAttribute(attributes.getIndex(LOCATION)); 173 attributes = attrsCopy; 174 } 175 contextWidget = pipeContext.findForm(formJXPath); 176 177 180 String localeAttr = attributes.getValue("locale"); 181 if (localeAttr != null) { localeAttr = pipeContext.translateText(localeAttr); 183 pipeContext.setLocale(I18nUtils.parseLocale(localeAttr)); 184 } else if (pipeContext.getLocaleParameter() != null) { pipeContext.setLocale(pipeContext.getLocaleParameter()); 186 } else { Object locale = null; 188 try { 189 locale = pipeContext.evaluateExpression("/locale"); 190 } catch (JXPathException e) {} 191 if (locale != null) { 192 pipeContext.setLocale((Locale )locale); 193 } 194 else { 195 pipeContext.setLocale(Locale.getDefault()); 197 } 198 } 199 200 String [] namesToTranslate = {"action"}; 201 Attributes 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 Object idObj = pipeContext.evaluateExpression("$continuation/id"); 208 if (idObj == null) { 209 throw new SAXException ("No continuation found"); 210 } 211 212 String 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 ("WoodyTemplateTransformer: Unsupported element: " + localName); 220 } 221 } else { 222 super.startElement(namespaceURI, localName, qName, attributes); 223 } 224 } 225 226 private void checkContextWidgetAvailable(String widgetElementName) throws SAXException { 227 if (contextWidget == null) 228 throw new SAXException (widgetElementName + " cannot be used outside a wt:form-template element"); 229 } 230 231 private Attributes translateAttributes(Attributes attributes, String [] names) { 232 AttributesImpl newAtts = new AttributesImpl (attributes); 233 if (names!= null) { 234 for (int i = 0; i < names.length; i++) { 235 String name = names[i]; 236 int position = newAtts.getIndex(name); 237 String newValue = pipeContext.translateText(newAtts.getValue(position)); 238 newAtts.setValue(position, newValue); 239 } 240 } 241 return newAtts; 242 } 243 244 245 protected Widget getWidget(Attributes attributes) throws SAXException { 246 String widgetId = attributes.getValue("id"); 247 if (widgetId == null || widgetId.equals("")) { 248 throw new SAXException ("WoodyTemplateTransformer: missing id attribute on a woody element."); 249 } 250 Widget widget = contextWidget.getWidget(widgetId); 251 if (widget == null) { 252 throw new SAXException ("WoodyTemplateTransformer: widget with id \"" + widgetId + "\" does not exist in the container " + contextWidget.getFullyQualifiedId()); 253 } 254 return widget; 255 } 256 257 public void endElement(String namespaceURI, String localName, String qName) 258 throws SAXException { 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 } 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 prefix, String uri) 308 throws SAXException { 309 if (inWidgetElement) { 310 saxBuffer.startPrefixMapping(prefix, uri); 311 } else { 312 super.startPrefixMapping(prefix, uri); 313 } 314 } 315 316 public void endPrefixMapping(String prefix) 317 throws SAXException { 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 { 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 { 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 target, String data) 344 throws SAXException { 345 if (inWidgetElement) { 346 saxBuffer.processingInstruction(target, data); 347 } else { 348 super.processingInstruction(target, data); 349 } 350 } 351 352 public void skippedEntity(String name) 353 throws SAXException { 354 if (inWidgetElement) { 355 saxBuffer.skippedEntity(name); 356 } else { 357 super.skippedEntity(name); 358 } 359 } 360 361 public void startEntity(String name) 362 throws SAXException { 363 if (inWidgetElement) 364 saxBuffer.startEntity(name); 365 else 366 super.startEntity(name); 367 } 368 369 public void endEntity(String name) 370 throws SAXException { 371 if (inWidgetElement) { 372 saxBuffer.endEntity(name); 373 } else { 374 super.endEntity(name); 375 } 376 } 377 378 public void startCDATA() 379 throws SAXException { 380 if (inWidgetElement) { 381 saxBuffer.startCDATA(); 382 } else { 383 super.startCDATA(); 384 } 385 } 386 387 public void endCDATA() 388 throws SAXException { 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 { 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 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 uri, String loc, String raw, Attributes a) 431 throws SAXException { 432 elementNesting++; 433 super.startElement(uri, loc, raw, a); 434 } 435 436 public void endElement(String uri, String loc, String raw) 437 throws SAXException { 438 elementNesting--; 439 if (elementNesting == 0 && saxBuffer != null) { 440 if (gotStylingElement) { 441 saxBuffer.toSAX(contentHandler); 443 } else { 444 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 |