1 10 package org.mmbase.bridge.jsp.taglib; 11 12 import org.mmbase.bridge.jsp.taglib.util.Attribute; 13 import org.mmbase.bridge.jsp.taglib.util.Referids; 14 15 import javax.servlet.jsp.*; 16 17 import javax.servlet.jsp.tagext.TagSupport ; 18 19 import org.w3c.dom.Document ; 20 21 import javax.xml.transform.Source ; 22 import javax.xml.transform.Templates ; 23 import javax.xml.transform.TransformerFactory ; 24 import javax.xml.parsers.DocumentBuilder ; 25 26 import org.mmbase.bridge.util.xml.Generator; 27 import org.mmbase.bridge.Cloud; 28 29 import java.net.URL ; 30 import java.util.*; 31 import javax.servlet.jsp.PageContext ; 32 33 import org.mmbase.util.Encode; 34 import org.mmbase.util.Entry; 35 import org.mmbase.util.logging.Logger; 36 import org.mmbase.util.logging.Logging; 37 38 import org.mmbase.cache.xslt.*; 39 40 41 48 public class FormatterTag extends CloudReferrerTag implements ParamHandler { 49 50 private static final Logger log = Logging.getLoggerInstance(FormatterTag.class); 51 52 53 protected Attribute xslt = Attribute.NULL; 54 protected Attribute format = Attribute.NULL; 55 protected Attribute options = Attribute.NULL; 56 protected Attribute wants = Attribute.NULL; 57 58 protected Attribute namespaceAware = Attribute.NULL; 59 protected Attribute referids = Attribute.NULL; 60 61 protected List extraParameters = new ArrayList(); 62 63 protected Source xsltSource = null; 64 65 private DocumentBuilder documentBuilder; 66 private DocumentBuilder documentBuilderNS; 67 private URL cwd; 68 69 private static final class Counter { 70 private int i = 0; 71 public int inc() { return ++i;} 72 public String toString() { 73 return "" + i; 74 } 75 } 76 private Counter counter; 78 private Cloud cloud; 79 80 82 private static final int FORMAT_XHTML = 1; 84 private static final int FORMAT_PRESENTXML = 2; 85 private static final int FORMAT_CODE = 3; 86 private static final int FORMAT_TEXTONLY = 4; 87 private static final int FORMAT_RICH = 5; 88 89 private static final int FORMAT_ESCAPEXMLPRETTY = 500; 91 92 93 private static final int FORMAT_LIMIT_WANTXML = 1000; 95 private static final int FORMAT_ESCAPEXML = 1001; 97 private static final int FORMAT_DATE = 1002; 98 private static final int FORMAT_LOWERCASE = 1003; 99 private static final int FORMAT_UPPERCASE = 1004; 100 private static final int FORMAT_NONE = 2000; 102 103 private static final int FORMAT_UNSET = -1; 104 105 106 private static final int WANTS_DEFAULT = -1; 107 private static final int WANTS_DOM = 1; 108 private static final int WANTS_STRING = 2; 109 110 private static final String PAGECONTEXT_COUNTER = "formatter__counter"; 111 112 113 Properties props = new Properties(); 114 115 { 116 log.debug("Init of FormatterTag."); 117 118 try { 119 javax.xml.parsers.DocumentBuilderFactory dfactory = javax.xml.parsers.DocumentBuilderFactory.newInstance(); 120 dfactory.setNamespaceAware(false); 121 documentBuilder = dfactory.newDocumentBuilder(); 122 dfactory.setNamespaceAware(true); 123 documentBuilderNS = dfactory.newDocumentBuilder(); 124 org.xml.sax.ErrorHandler handler = new org.mmbase.util.XMLErrorHandler(); 125 org.xml.sax.EntityResolver resolver = new org.mmbase.util.XMLEntityResolver(); 126 documentBuilder.setErrorHandler(handler); 127 documentBuilder.setEntityResolver(resolver); 128 documentBuilderNS.setErrorHandler(handler); 129 documentBuilderNS.setEntityResolver(resolver); 130 } catch (Exception e) { 131 log.error(e.toString()); 132 } 133 } 134 135 139 private Generator xmlGenerator = null; 140 141 144 protected int timerHandle; 145 146 149 public void setXslt(String x) throws JspTagException { 150 xslt = getAttribute(x); 151 } 152 153 156 public void setFormat(String f) throws JspTagException { 157 format = getAttribute(f); 158 } 159 160 protected int getFormat() throws JspTagException { 161 String fs = format.getString(this).toLowerCase(); 162 if ("".equals(fs)) { 163 return FORMAT_UNSET; 164 } else if ("none".equals(fs)) { 165 return FORMAT_NONE; 166 } else if ("xhtml".equals(fs)) { 167 return FORMAT_XHTML; 168 } else if ("presentxml".equals(fs)) { 169 return FORMAT_PRESENTXML; 170 } else if ("code".equals(fs)) { 171 return FORMAT_CODE; 172 } else if ("escapexml".equals(fs)) { 173 return FORMAT_ESCAPEXML; 174 } else if ("escapexmlpretty".equals(fs)) { 175 return FORMAT_ESCAPEXMLPRETTY; 176 } else if ("date".equals(fs)) { 177 return FORMAT_DATE; 178 } else if ("textonly".equals(fs)) { 179 return FORMAT_TEXTONLY; 180 } else if ("rich".equals(fs)) { 181 return FORMAT_RICH; 182 } else { 183 throw new JspTagException("Unknown format " + fs); 184 } 185 } 186 187 190 public void setOptions(String o) throws JspTagException { 191 options = getAttribute(o); 192 } 193 194 public void setWants(String w) throws JspTagException { 195 wants = getAttribute(w); 196 } 197 protected int getWants() throws JspTagException { 198 if (wants == Attribute.NULL) return WANTS_DEFAULT; 199 String ww = wants.getString(this).toLowerCase(); 200 if ("default".equals(ww)) { 201 return WANTS_DEFAULT; 202 } else if ("dom".equals(ww)) { 203 return WANTS_DOM; 204 } else if ( "string".equals(ww)) { 205 return WANTS_STRING; 206 } else { 207 throw new JspTagException("Unknown value '" + ww + "' for wants attribute."); 208 } 209 } 210 211 public void setNamespaceaware(String n) throws JspTagException { 212 namespaceAware = getAttribute(n); 213 } 214 215 public void setReferids(String r) throws JspTagException { 216 referids = getAttribute(r); 217 } 218 219 public void addParameter(String key, Object value) throws JspTagException { 220 if (log.isDebugEnabled()) { 221 log.debug("adding parameter " + key + "/" + value); 222 } 223 extraParameters.add(new Entry(key, value)); 224 } 225 228 public void setXsltSource(Source xs) { 229 xsltSource = xs; 230 } 231 232 233 237 public Generator getGenerator() { 238 return xmlGenerator; 239 } 240 241 246 public final boolean wantXML() { 247 return xmlGenerator != null; 248 } 249 250 254 public boolean setCloud(Cloud c) { 255 boolean result = cloud == null; 256 if (result) { 257 cloud = c; 258 } 259 return result; 260 } 261 262 263 public void setPageContext(PageContext pageContext) { 264 super.setPageContext(pageContext); 265 javax.servlet.http.HttpServletRequest request = (javax.servlet.http.HttpServletRequest )pageContext.getRequest(); 266 try { 267 String includingServlet = (String ) request.getAttribute(org.mmbase.bridge.jsp.taglib.pageflow.IncludeTag.INCLUDE_PATH_KEY); 268 if (includingServlet == null) { 269 includingServlet = request.getServletPath(); 270 } 271 cwd = pageContext.getServletContext().getResource(org.mmbase.util.ResourceLoader.getDirectory(includingServlet) + "/"); 272 } catch (Exception e) { 273 } 274 } 275 276 277 public int doStartTag() throws JspTagException { 278 extraParameters.clear(); 279 cloud = null; 280 counter = (Counter) pageContext.getAttribute(PAGECONTEXT_COUNTER); 281 if (counter == null) { 282 log.debug("counter not found"); 283 counter = new Counter(); 284 pageContext.setAttribute(PAGECONTEXT_COUNTER, counter); 285 } 286 counter.inc(); 287 288 if (log.isDebugEnabled()) log.debug("startag of formatter tag " + counter); 289 290 TagSupport t = findParentTag(org.mmbase.bridge.jsp.taglib.debug.TimerTag.class, null, false); 292 if (t != null) { 293 timerHandle = ((org.mmbase.bridge.jsp.taglib.debug.TimerTag)t).startTimer(getId(), getClass().getName()); 294 } else { 295 timerHandle = -1; 296 } 297 298 xsltSource = null; 299 300 if (format != Attribute.NULL && xslt != Attribute.NULL) { 301 throw new JspTagException ("One of the attributes xslt and format must be specified, or none (then you have to use an mm:xslt subtag."); 302 } 303 304 int w = getWants(); 305 if ((w == WANTS_DEFAULT && getFormat() < FORMAT_LIMIT_WANTXML) || w == WANTS_DOM) { if(namespaceAware.getBoolean(this, true)) { 307 xmlGenerator = new Generator(documentBuilderNS); 308 xmlGenerator.setNamespaceAware(true); 309 } else { 310 xmlGenerator = new Generator(documentBuilder); 311 xmlGenerator.setNamespaceAware(false); 312 } 313 } else { 314 xmlGenerator = null; } 316 317 return EVAL_BODY_BUFFERED; 318 } 319 320 public int doAfterBody() throws JspException { 321 return helper.doAfterBody(); 322 } 323 324 325 public int doEndTag() throws JspTagException { 326 if (helper.getJspvar() == null) { 327 helper.overrideWrite(true); 328 } 329 330 Document doc; 331 332 String body = bodyContent.getString().trim(); 333 bodyContent.clearBody(); 335 if(getFormat() < FORMAT_LIMIT_WANTXML) { if (xmlGenerator != null && xmlGenerator.getDocument().getDocumentElement().getFirstChild() != null) { 337 if (body.length() > 0) { 338 throw new JspTagException ("It is not possible to have tags which produce DOM-XML and text in the body. Perhaps you want to use the attribute wants='string'?"); 339 } else { 340 doc = xmlGenerator.getDocument(); 341 } 342 } else { 343 if (body == null || body.equals("")) body = "<mmxf />"; if (log.isDebugEnabled()) log.debug("Using bodycontent as input:>" + body + "<"); 345 try { 346 String encoding = org.mmbase.util.GenericResponseWrapper.getXMLEncoding(body); 347 if (encoding == null) encoding = "UTF-8"; javax.servlet.http.HttpServletRequest request = (javax.servlet.http.HttpServletRequest )pageContext.getRequest(); 349 DocumentBuilder db = namespaceAware.getBoolean(this, true) ? documentBuilderNS : documentBuilder; 350 doc = db.parse(new java.io.ByteArrayInputStream (body.getBytes(encoding)), 351 pageContext.getServletContext().getResource(request.getServletPath()).toString() 352 ); 353 } catch (Exception e) { 354 throw new TaglibException(e.getMessage() + "when parsing '" + body + "'", e); 355 } 356 if (log.isDebugEnabled()) { 357 log.debug("created an element: " + doc.getDocumentElement().getTagName()); 358 } 359 } 360 361 } else { 362 doc = null; 363 } 364 365 366 if (log.isDebugEnabled()) { 367 if (doc != null) { 368 log.trace("XSL converting document: " + prettyXML(doc)); 369 } else { 370 log.trace("Converting: " + body); 371 } 372 } 373 374 375 381 if (format != Attribute.NULL) { 382 if (xslt != Attribute.NULL) { 383 throw new JspTagException("Cannot specify both the 'xslt' attribute and the 'format' attribute"); 384 } 385 if (xsltSource != null) { 386 throw new JspTagException("Cannot use 'xslt' subtag and the 'format' attribute"); 387 } 388 switch(getFormat()) { 389 case FORMAT_NONE: 390 helper.useEscaper(true); 391 helper.setValue(body); 392 break; 393 case FORMAT_XHTML: 394 helper.useEscaper(false); helper.setValue(xslTransform(doc, "xslt/2xhtml.xslt")); 396 break; 397 case FORMAT_PRESENTXML: 398 helper.useEscaper(false); helper.setValue(xslTransform(doc, "xslt/2xml.xslt")); 400 break; 401 case FORMAT_CODE: 402 helper.setValue(xslTransform(doc, "xslt/code2xml.xslt")); 403 break; 404 case FORMAT_TEXTONLY: 405 helper.useEscaper(true); 406 helper.setValue(xslTransform(doc, "xslt/2ascii.xslt")); 407 break; 408 case FORMAT_RICH: 409 helper.useEscaper(false); helper.setValue(xslTransform(doc, "xslt/mmxf2rich.xslt")); 411 break; 412 case FORMAT_ESCAPEXMLPRETTY: 413 helper.useEscaper(false); helper.setValue(Encode.encode("ESCAPE_XML", prettyXML(doc))); 415 break; 417 case FORMAT_ESCAPEXML: 419 helper.useEscaper(false); helper.setValue(Encode.encode("ESCAPE_XML", body)); 421 break; 422 case FORMAT_DATE: 423 java.text.SimpleDateFormat dateFormat = (java.text.SimpleDateFormat ) java.text.SimpleDateFormat.getDateInstance(); 424 String pattern; 425 if (options == Attribute.NULL) { 426 pattern = "yyyy-MM-dd HH:mm:ss"; 427 } else { 428 pattern = options.getString(this); 429 } 430 dateFormat.applyPattern(pattern); 432 Date datum = new Date((new Long (body)).longValue() * 1000); 433 helper.setValue(dateFormat.format(datum)); 434 break; 435 default: 436 log.debug("Unknown format "+getFormat()); 437 break; 438 } 439 } else { 440 441 if (xslt != Attribute.NULL) { 442 if (xsltSource != null) { 443 throw new JspTagException("Cannot use 'xslt' subtag and the 'xslt' attribute"); 444 } 445 if (log.isDebugEnabled()) log.debug("Transforming with " + xslt.getString(this)); 446 447 helper.setValue(xslTransform(doc, xslt.getString(this))); 448 } else { 449 if (xsltSource == null) { 450 throw new JspTagException("No 'format' attribute, no 'xslt' attribute and no 'xslt' subtag. Don't know what to do."); 451 } 452 helper.setValue(xslTransform(doc, xsltSource)); 453 } 454 } 455 456 if (log.isDebugEnabled()) { 457 log.trace("found result " + helper.getValue()); 458 459 } 460 461 462 if (getId() != null) { 463 getContextProvider().getContextContainer().register(getId(), helper.getValue()); 464 } 465 466 if (timerHandle != -1) { 467 ((org.mmbase.bridge.jsp.taglib.debug.TimerTag)findParentTag(org.mmbase.bridge.jsp.taglib.debug.TimerTag.class, null, false)).haltTimer(timerHandle); 468 } 469 helper.doEndTag(); 470 return super.doEndTag(); 471 } 473 public void doFinally() { 474 xsltSource = null; 475 props = null; 476 if (helper != null) { 477 helper.doFinally(); 478 } 479 if (extraParameters != null) { 480 extraParameters.clear(); 481 } 482 xmlGenerator = null; 483 cloud = null; 484 super.doFinally(); 485 } 486 487 490 491 private TransformerFactory getFactory() { 492 return FactoryCache.getCache().getFactory(cwd); 493 } 494 495 503 private String xslTransform(Document doc, Source xsl) throws JspTagException { 504 if (log.isDebugEnabled()) { 505 log.debug("transforming in " + cwd + " with " + xsl.getSystemId()); 506 } 507 508 TemplateCache cache= TemplateCache.getCache(); 509 Templates cachedXslt = cache.getTemplates(xsl); 510 if (cachedXslt == null) { 511 try { 512 if (log.isDebugEnabled()) { 513 log.debug("getting for " + cwd); 514 } 515 cachedXslt = getFactory().newTemplates(xsl); 516 assert cachedXslt != null; cache.put(xsl, cachedXslt); 518 } catch (javax.xml.transform.TransformerConfigurationException e) { 519 return e.toString() + ": " + Logging.stackTrace(e); 520 } 521 } else { 522 if (log.isDebugEnabled()) log.debug("Used xslt from cache with " + xsl.getSystemId()); 523 } 524 525 if (cachedXslt == null) { 526 throw new JspTagException("Could not create Templates object from " + xsl.getSystemId() + " " + xsl); 529 } 530 531 Map params = new HashMap(); 533 String context = ((javax.servlet.http.HttpServletRequest )pageContext.getRequest()).getContextPath(); 534 params.put("formatter_requestcontext", context); 535 LocaleTag localeTag = (LocaleTag) findParentTag(org.mmbase.bridge.jsp.taglib.LocaleTag.class, null, false); 538 Locale locale; 539 if (localeTag != null) { 540 locale = localeTag.getLocale(); 541 if (locale == null) { 542 locale = Locale.getDefault(); } 544 } else { 545 locale = Locale.getDefault(); } 547 params.put("formatter_language", locale.getLanguage()); 548 params.put("formatter_counter", counter.toString()); 549 if (cloud != null) { 550 params.put("cloud", cloud); 551 } else { 552 CloudProvider cp = findCloudProvider(false); 553 if (cp != null) { 554 params.put("cloud", cp.getCloudVar()); 555 } 556 } 557 params.put("request", pageContext.getRequest()); 558 559 if (options != Attribute.NULL) { 562 Iterator i = options.getList(this).iterator(); 563 while (i.hasNext()) { 564 String option = (String ) i.next(); 565 List o = Arrays.asList( option.trim().split("\\s*=\\s*") ); 567 if (o.size() != 2) { 568 throw new JspTagException("Option '" + option + "' is not in the format key=value (required for XSL transformations)"); 569 570 } else { 571 if (log.isDebugEnabled()) log.debug("Setting XSLT option " + option); 572 params.put(o.get(0), o.get(1)); 573 } 574 } 575 } 576 params.putAll(Referids.getReferids(referids, this)); 577 Iterator i = extraParameters.iterator(); 578 while (i.hasNext()) { 579 Map.Entry entry = (Map.Entry) i.next(); 580 params.put(entry.getKey(), entry.getValue()); 581 } 582 583 return ResultCache.getCache().get(cachedXslt, xsl, params, props, doc); 584 585 } 586 public void setOutputProperties(Properties properties) { 587 this.props = properties; 588 } 589 593 private String xslTransform(Document doc, String xsl) throws JspTagException { 594 try { 595 Source source = getFactory().getURIResolver().resolve(xsl, null); 596 if (source == null) { 597 throw new TaglibException("Could not find XSL for " + xsl + " with uri-resolver " + getFactory().getURIResolver()); 598 } 599 600 return xslTransform(doc, source); 601 } catch (javax.xml.transform.TransformerException e) { 602 throw new TaglibException(e); } 604 } 605 606 private String prettyXML(Document doc) throws JspTagException { 607 if ( log.isTraceEnabled() ) { 608 log.trace("pretty XML " + doc); 609 } 610 return xslTransform(doc, "xslt/indentxml.xslt"); 611 } 612 613 } 614 | Popular Tags |