1 10 package org.mmbase.bridge.jsp.taglib; 11 12 import org.mmbase.bridge.jsp.taglib.util.Attribute; 13 import javax.servlet.jsp.JspTagException ; 14 import javax.servlet.jsp.PageContext ; 15 import javax.servlet.http.*; 16 17 import java.util.*; 18 import java.io.InputStream ; 19 import java.net.URL ; 20 import java.net.URLConnection ; 21 22 import org.mmbase.util.transformers.*; 23 import org.mmbase.util.xml.DocumentReader; 24 import org.mmbase.util.functions.Parameters; 25 26 import org.mmbase.util.*; 27 import org.mmbase.security.UserContext; 28 29 import org.xml.sax.InputSource ; 30 import org.w3c.dom.Element ; 31 32 33 import org.mmbase.util.logging.Logger; 34 import org.mmbase.util.logging.Logging; 35 36 43 44 public class ContentTag extends LocaleTag { 45 private static Logger log; 46 47 48 static final CharTransformer COPY = CopyCharTransformer.INSTANCE; 49 50 private static final long DEFAULT_EXPIRE_TIME = 60; 52 public static final String ESCAPER_KEY = "org.mmbase.bridge.jsp.taglib.escaper"; 53 54 static final ContentTag DEFAULT = new ContentTag() { 55 public CharTransformer getWriteEscaper() { return COPY; } 56 public String getType() { return "text/html"; } 57 public String getEncoding(){ return "ISO-8859-1"; } 58 }; 59 60 private static final Map defaultEscapers = new HashMap(); private static final Map defaultPostProcessors = new HashMap(); private static final Map defaultEncodings = new HashMap(); 64 private static final Map contentTypes = new HashMap(); 66 private static final Map charTransformers = new HashMap(); private static final Map parameterizedCharTransformerFactories = new HashMap(); 69 static { 70 try { 71 log = Logging.getLoggerInstance(ContentTag.class); 72 org.mmbase.util.XMLEntityResolver.registerPublicID("-//MMBase//DTD taglibcontent 1.0//EN", "taglibcontent_1_0.dtd", ContentTag.class); 73 ResourceWatcher watcher = new ResourceWatcher(ResourceLoader.getConfigurationRoot().getChildResourceLoader("taglib")) { 74 public void onChange(String resource) { 75 defaultEscapers.clear(); 76 defaultPostProcessors.clear(); 77 defaultEncodings.clear(); 78 charTransformers.clear(); 79 parameterizedCharTransformerFactories.clear(); 80 contentTypes.clear(); 81 initialize(getResourceLoader(), resource); 82 } 83 }; 84 watcher.add("content.xml"); 85 watcher.start(); 86 watcher.onChange("content.xml"); 87 } catch (Exception e) { 88 log.error(e.toString()); 89 } 90 } 91 92 93 private static CharTransformer readCharTransformer(DocumentReader reader, Element parentElement, String id) { 94 List result = new ArrayList(); 95 Iterator e = reader.getChildElements(parentElement, "class"); 96 while (e.hasNext()) { 97 Element element = (Element ) e.next(); 98 String claz = reader.getElementValue(element); 99 100 String config = element.getAttribute("config"); 101 boolean back = "true".equalsIgnoreCase(element.getAttribute("back")); 102 103 CharTransformer ct = Transformers.getCharTransformer(claz, config, " escaper " + id, back); 104 if (ct == null) continue; 105 result.add(ct); 106 } 107 if (result.size() == 0) { 108 return COPY; 109 } else if (result.size() == 1) { 110 return (CharTransformer) result.get(0); 111 } else { 112 ChainedCharTransformer cct = new ChainedCharTransformer(); 113 cct.addAll(result); 114 return cct; 115 } 116 } 117 118 private static ParameterizedTransformerFactory readTransformerFactory(final DocumentReader reader, final Element parentElement, final String id) { 119 Iterator e = reader.getChildElements(parentElement, "class"); 120 Element element = (Element ) e.next(); 121 final String claz = reader.getElementValue(element); 122 123 e = reader.getChildElements(parentElement, "param"); 124 final Map configuredParams = new HashMap(); 125 while (e.hasNext()) { 126 Element param = (Element ) e.next(); 127 String name = param.getAttribute("name"); 128 String value = param.getAttribute("value"); 129 if (! value.equals("")) { 130 configuredParams.put(name, value); 131 } 132 } 133 if (configuredParams.size() == 0) { 134 return Transformers.getTransformerFactory(claz, " parameterizedescaper " + id); 135 } else { 136 return new ParameterizedTransformerFactory() { 137 ParameterizedTransformerFactory wrapped = Transformers.getTransformerFactory(claz, " parameterizedescaper " + id); 138 139 public Transformer createTransformer(Parameters parameters) { 140 return wrapped.createTransformer(parameters); 141 } 142 public Parameters createParameters() { 143 Parameters params = wrapped.createParameters(); 144 params.setAll(configuredParams); 145 return params; 146 } 147 148 }; 149 } 150 } 151 154 private static void initialize(ResourceLoader taglibLoader, String resource) { 155 log.service("Reading taglib write-escapers"); 156 InputStream stream = ContentTag.class.getResourceAsStream("resources/taglibcontent.xml"); 157 if (stream != null) { 158 log.service("Reading backwards compatible resource " + ContentTag.class.getName() + "/resources/taglibcontent.xml"); 159 InputSource escapersSource = new InputSource (stream); 160 readXML(escapersSource); 161 } 162 List resources = taglibLoader.getResourceList(resource); 163 log.service("Using " + resources); 164 ListIterator i = resources.listIterator(); 165 while (i.hasNext()) i.next(); 166 while (i.hasPrevious()) { 167 try { 168 URL u = (URL ) i.previous(); 169 log.debug("Reading " + u); 170 URLConnection con = u.openConnection(); 171 if (con.getDoInput()) { 172 InputSource source = new InputSource (con.getInputStream()); 173 readXML(source); 174 } 175 } catch (Exception e) { 176 log.error(e); 177 } 178 } 179 { 180 List l = new ArrayList(charTransformers.keySet()); 181 Collections.sort(l); 182 log.service("Found escapers: " + l); 183 l = new ArrayList(parameterizedCharTransformerFactories.keySet()); 184 Collections.sort(l); 185 log.service("Found parameterized escapers: " + l); 186 l = new ArrayList(contentTypes.keySet()); 187 Collections.sort(l); 188 log.service("Recognized content-types: " + l); 189 } 190 191 } 192 193 protected static void readXML(InputSource escapersSource) { 194 195 DocumentReader reader = new DocumentReader(escapersSource, ContentTag.class); 196 Element root = reader.getElementByPath("taglibcontent"); 197 198 for (Iterator iter = reader.getChildElements(root, "escaper"); iter.hasNext();) { 199 Element element = (Element ) iter.next(); 200 String id = element.getAttribute("id"); 201 CharTransformer ct = readCharTransformer(reader, element, id); 202 CharTransformer prev = (CharTransformer) charTransformers.put(id, ct); 203 if (prev != null) { 204 log.warn("Replaced an escaper '" + id + "' : " + ct + "(was " + prev + ")"); 205 } else { 206 log.debug("Found an escaper '" + id + "' : " + ct); 207 } 208 209 } 210 211 log.debug("Reading content tag parameterizedescaperss"); 212 for (Iterator iter = reader.getChildElements(root, "parameterizedescaper"); iter.hasNext();) { 213 Element element = (Element ) iter.next(); 214 String id = element.getAttribute("id"); 215 ParameterizedTransformerFactory fact = readTransformerFactory(reader, element, id); 216 ParameterizedTransformerFactory prev = (ParameterizedTransformerFactory) parameterizedCharTransformerFactories.put(id, fact); 217 if (prev != null) { 218 log.warn("Replaced an parameterized escaper '" + id + "' : " + fact + " (was " + prev + ")"); 219 } else { 220 log.debug("Found an parameterized escaper '" + id + "' : " + fact); 221 } 222 223 try { 224 CharTransformer ct = (CharTransformer) fact.createTransformer(fact.createParameters()); 225 if (! charTransformers.containsKey("id")) { 226 log.debug("Could be instantiated with default parameters too"); 227 charTransformers.put(id, ct); 228 } else { 229 log.service("Already a chartransformer with id " + id); 230 } 231 } catch (Exception ex) { 232 log.debug("Could not be instantiated with default parameters only: " + ex.getMessage()); 233 } 234 235 } 236 237 238 Set postProcessors = new HashSet(); 239 log.debug("Reading content tag post-processors"); 240 for (Iterator iter = reader.getChildElements(root, "postprocessor"); iter.hasNext();) { 241 Element element = (Element ) iter.next(); 242 String id = element.getAttribute("id"); 243 CharTransformer ct = readCharTransformer(reader, element, id); 244 CharTransformer prev = (CharTransformer) charTransformers.put(id, ct); 245 if (prev != null) { 246 log.warn("Replaced an postprocessor '" + id + "' : " + ct + " (was " + prev + ")"); 247 } else { 248 log.debug("Found an postprocessor '" + id + "' : " + ct); 249 } 250 postProcessors.add(id); 251 } 252 if (postProcessors.size() > 0) { 253 log.service("Found post-processors: " + postProcessors); 254 } 255 256 for (Iterator iter = reader.getChildElements(root, "content"); iter.hasNext();) { 257 Element element = (Element ) iter.next(); 258 String type = element.getAttribute("type"); 259 String id = element.getAttribute("id"); 260 if (id.equals("")) { 261 id = type; 262 } 263 contentTypes.put(id, type); 264 String defaultEscaper = element.getAttribute("defaultescaper"); 265 if (! defaultEscaper.equals("")) { 266 if (charTransformers.containsKey(defaultEscaper)) { 267 defaultEscapers.put(id, defaultEscaper); 268 } else { 269 log.warn("Default escaper '" + defaultEscaper + "' for type + '"+ type + "' is not known"); 270 } 271 } 272 String defaultPostprocessor = element.getAttribute("defaultpostprocessor"); 273 if (! defaultPostprocessor.equals("")) { 274 if (charTransformers.containsKey(defaultPostprocessor)) { 275 defaultPostProcessors.put(id, defaultPostprocessor); 276 } else { 277 log.warn("Default postprocessor '" + defaultPostprocessor + "' for type + '"+ type + "' is not known"); 278 } 279 } 280 String defaultEncoding = element.getAttribute("defaultencoding"); 281 if (! defaultEncoding.equals("NOTSPECIFIED")) { 282 defaultEncodings.put(id, defaultEncoding); 283 } 284 } 285 286 } 287 288 289 private Attribute type = Attribute.NULL; 290 private Attribute encoding = Attribute.NULL; 291 private Attribute escaper = Attribute.NULL; 292 private Attribute postprocessor = Attribute.NULL; 293 private Attribute expires = Attribute.NULL; 294 private Attribute status = Attribute.NULL; 295 private Attribute refresh = Attribute.NULL; 296 297 298 public void setType(String ct) throws JspTagException { 299 type = getAttribute(ct); 300 } 301 302 public void setEncoding(String e) throws JspTagException { 303 encoding = getAttribute(e); 304 } 305 306 public void setEscaper(String e) throws JspTagException { 307 escaper = getAttribute(e); 308 } 309 310 public void setPostprocessor(String e) throws JspTagException { 311 postprocessor = getAttribute(e); 312 } 313 314 public void setExpires(String e) throws JspTagException { 315 expires = getAttribute(e); 316 } 317 318 319 public String getType() throws JspTagException { 320 if (type == Attribute.NULL) { 321 return "text/html"; } else { 323 String ct = type.getString(this); 324 String c = (String ) contentTypes.get(ct); 325 if (c != null) return c; 326 return ct; 327 } 328 } 329 330 public void setStatus(String s) throws JspTagException { 331 status = getAttribute(s); 332 } 333 public void setRefresh(String r) throws JspTagException { 334 refresh = getAttribute(r); 335 } 336 337 338 339 344 345 346 350 protected CharTransformer getPostProcessor() throws JspTagException { 351 if (! postprocessor.getString(this).equals("")) { 352 return getCharTransformer(postprocessor.getString(this), this); 353 } else { 354 if (type != Attribute.NULL) { 355 String defaultPostProcessor = (String ) defaultPostProcessors.get(type.getString(this)); 356 if (defaultPostProcessor != null) { 357 return getCharTransformer(defaultPostProcessor, this); 358 } 359 } 360 return null; 361 } 362 } 363 364 365 public String getEncoding() throws JspTagException { 366 if (encoding == Attribute.NULL) { 367 String defaultEncoding = (String ) defaultEncodings.get(getType()); 368 if (defaultEncoding == null) { 369 return "UTF-8"; } else { 371 return defaultEncoding; 372 } 373 } else { 374 return encoding.getString(this); 375 } 376 } 377 378 382 protected static CharTransformer getSimpleCharTransformer(String id, ContextReferrerTag tag) throws JspTagException { 383 CharTransformer c = (CharTransformer) charTransformers.get(id); 384 if (c == null && tag != null) c = (CharTransformer) tag.getContextProvider().getContextContainer().get(id); 385 if (c == null) { 386 int paramsPos = id.indexOf('('); 387 if (paramsPos > 0 && id.charAt(id.length() - 1) == ')') { String parameterized = id.substring(0, paramsPos); 390 ParameterizedTransformerFactory factory = getTransformerFactory(parameterized); 391 Parameters parameters = factory.createParameters(); 392 parameters.setAutoCasting(true); 393 if (tag != null) { 394 tag.fillStandardParameters(parameters); 395 } 396 parameters.setAll(StringSplitter.split(id.substring(paramsPos + 1, id.length() - 1))); 397 c = (CharTransformer) factory.createTransformer(parameters); 398 } else { 399 ParameterizedTransformerFactory factory = getTransformerFactory(id); 401 log.debug("Found factory for " + id + " " + factory); 402 if (factory != null) { 403 Parameters parameters = factory.createParameters(); 404 parameters.setAutoCasting(true); 405 if (tag != null) { 406 tag.fillStandardParameters(parameters); 407 } 408 c = (CharTransformer) factory.createTransformer(parameters); 409 } 410 } 411 } 412 if (c == null) throw new JspTagException ("The chartransformer " + id + " is unknown"); 413 return c; 414 } 415 416 422 423 public static CharTransformer getCharTransformer(String id, ContextReferrerTag tag) throws JspTagException { 424 425 List transs = org.mmbase.util.StringSplitter.splitFunctions(id); 426 427 if (transs.size() > 1) { 428 ChainedCharTransformer ct = new ChainedCharTransformer(); 429 Iterator ids = transs.iterator(); 431 while (ids.hasNext()) { 432 String i = (String ) ids.next(); 433 CharTransformer c = getSimpleCharTransformer(i, tag); 434 if (ct != COPY) { 435 ct.add(c); 436 } 437 } 438 return ct; 439 } else { 440 CharTransformer ct = getSimpleCharTransformer(id, tag); 441 if (ct != COPY) { 442 return ct; 443 } else { 444 return null; 445 } 446 447 } 448 } 449 450 453 public static ParameterizedTransformerFactory getTransformerFactory(String id) throws JspTagException { 454 ParameterizedTransformerFactory fact = (ParameterizedTransformerFactory) parameterizedCharTransformerFactories.get(id); 455 if (fact == null) throw new JspTagException ("The chartransformerfactory " + id + " is unknown"); 456 return fact; 457 } 458 459 463 464 public CharTransformer getWriteEscaper() { 465 return (CharTransformer) pageContext.findAttribute(ESCAPER_KEY); 466 } 467 private CharTransformer prevEscaper = null; 468 469 protected void setWriteEscaper() throws JspTagException { 470 prevEscaper = getWriteEscaper(); 471 CharTransformer esc; 472 if (! escaper.getString(this).equals("")) { 473 esc = getCharTransformer(escaper.getString(this), this); 474 } else { 475 String defaultEscaper = (String ) defaultEscapers.get(getType()); 476 if (defaultEscaper != null) { 477 esc = getCharTransformer(defaultEscaper, this); 478 } else { 479 esc = COPY; 480 } 481 } 482 pageContext.setAttribute(ESCAPER_KEY, esc, PageContext.REQUEST_SCOPE); 483 } 484 protected void unsetWriteEscaper() { 485 if (prevEscaper == null) { 486 pageContext.removeAttribute(ESCAPER_KEY, PageContext.REQUEST_SCOPE); 487 } else { 488 pageContext.setAttribute(ESCAPER_KEY, prevEscaper, PageContext.REQUEST_SCOPE); 489 } 490 } 491 492 495 protected void determineLocale() throws JspTagException { 496 determineLocaleFromAttributes(); 498 if (locale == null) { 499 determineFromCloudProvider(); 500 } 501 } 502 503 public int doStartTag() throws JspTagException { 504 super.doStartTag(); 505 setWriteEscaper(); 506 String type = getType(); 507 508 addedCacheHeaders = false; 509 if (! type.equals("")) { 510 HttpServletResponse response = (HttpServletResponse) pageContext.getResponse(); 511 HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); 512 if (locale != null) { 513 response.setLocale(locale); 514 } 515 String enc = getEncoding(); 516 log.debug("Found encoding " + enc); 517 if (enc.equals("")) { 518 response.setContentType(getType()); } else { 520 response.setContentType(getType() + ";charset=" + enc); 521 } 522 523 if (expires == Attribute.NULL && request.getSession(false) == null) { addNoCacheHeaders(request, response, DEFAULT_EXPIRE_TIME); 525 } else { 526 long exp = expires.getLong(this, DEFAULT_EXPIRE_TIME); 529 addNoCacheHeaders(request, response, exp); 530 } 531 } 532 if (getPostProcessor() == null) { 533 log.debug("no postprocessor"); 534 return EVAL_BODY; 535 } else { 536 return EVAL_BODY_BUFFERED; 537 } 538 } 539 private boolean addedCacheHeaders = false; 540 541 556 protected void addNoCacheHeaders(HttpServletRequest request, HttpServletResponse response, long expire) { 557 if (request.getAttribute(org.mmbase.bridge.jsp.taglib.pageflow.IncludeTag.INCLUDE_PATH_KEY) == null) { 558 if (expire <= 0) { 559 response.setHeader("Cache-Control","no-cache, no-store, must-revalidate, proxy-revalidate"); 562 response.addHeader("Cache-Control", "post-check=0, pre-check=0"); 564 response.setHeader("Pragma", "no-cache"); 566 response.setDateHeader ("Expires", -1); 567 568 } else { 574 response.setDateHeader ("Expires", System.currentTimeMillis() + (expire * 1000)); 576 response.setHeader("Cache-Control", "public"); 577 } 578 addedCacheHeaders = true; 579 } else { 580 addedCacheHeaders = false; 581 } 582 } 583 584 public int doEndTag() throws JspTagException { 585 unsetWriteEscaper(); 586 return super.doEndTag(); 587 } 588 589 590 593 594 void setUser(UserContext newUser) throws JspTagException { 595 if (addedCacheHeaders) { 596 if (newUser != null) { 597 long exp = expires.getLong(this, DEFAULT_EXPIRE_TIME); 598 if (exp > 0) { 599 HttpServletResponse response = (HttpServletResponse) pageContext.getResponse(); 600 if (! response.containsHeader("Cache-Control")) { 601 response.setHeader("Cache-Control", "private"); 603 } 604 } 605 } 606 } 607 } 608 609 public int doAfterBody() throws JspTagException { 610 if (bodyContent != null) { 611 CharTransformer post = getPostProcessor(); 612 if (post != null) { 613 if (log.isDebugEnabled()) { 614 log.debug("A postprocessor was defined " + post); 615 } 617 618 post.transform(bodyContent.getReader(), bodyContent.getEnclosingWriter()); 619 620 } else { 621 if (EVAL_BODY == EVAL_BODY_BUFFERED) { 622 try { 624 if (bodyContent != null) { 625 bodyContent.writeOut(bodyContent.getEnclosingWriter()); 626 } 627 } catch (java.io.IOException ioe){ 628 throw new TaglibException(ioe); 629 } 630 } 631 } 632 } 633 return SKIP_BODY; 634 } 635 636 637 638 } 639 640 | Popular Tags |