| 1 16 package org.apache.cocoon.generation; 17 18 import java.beans.PropertyDescriptor ; 19 import java.io.CharArrayReader ; 20 import java.io.IOException ; 21 import java.io.PrintStream ; 22 import java.io.PrintWriter ; 23 import java.io.Serializable ; 24 import java.io.StringReader ; 25 import java.lang.reflect.Field ; 26 import java.lang.reflect.InvocationTargetException ; 27 import java.lang.reflect.Method ; 28 import java.text.DateFormat ; 29 import java.text.DecimalFormat ; 30 import java.text.DecimalFormatSymbols ; 31 import java.text.NumberFormat ; 32 import java.text.SimpleDateFormat ; 33 import java.util.Enumeration ; 34 import java.util.HashMap ; 35 import java.util.Iterator ; 36 import java.util.LinkedList ; 37 import java.util.List ; 38 import java.util.Locale ; 39 import java.util.Map ; 40 import java.util.Properties ; 41 import java.util.Stack ; 42 import java.util.TimeZone ; 43 44 import org.apache.avalon.framework.parameters.Parameters; 45 import org.apache.avalon.framework.service.ServiceException; 46 import org.apache.avalon.framework.service.ServiceManager; 47 import org.apache.cocoon.ProcessingException; 48 import org.apache.cocoon.caching.CacheableProcessingComponent; 49 import org.apache.cocoon.components.flow.FlowHelper; 50 import org.apache.cocoon.components.flow.WebContinuation; 51 import org.apache.cocoon.components.flow.javascript.fom.FOM_JavaScriptFlowHelper; 52 import org.apache.cocoon.components.source.SourceUtil; 53 import org.apache.cocoon.environment.ObjectModelHelper; 54 import org.apache.cocoon.environment.Request; 55 import org.apache.cocoon.environment.SourceResolver; 56 import org.apache.cocoon.transformation.ServiceableTransformer; 57 import org.apache.cocoon.util.jxpath.NamespacesTablePointer; 58 import org.apache.cocoon.util.location.LocatedRuntimeException; 59 import org.apache.cocoon.util.location.Location; 60 import org.apache.cocoon.util.location.LocationUtils; 61 import org.apache.cocoon.xml.IncludeXMLConsumer; 62 import org.apache.cocoon.xml.NamespacesTable; 63 import org.apache.cocoon.xml.RedundantNamespacesFilter; 64 import org.apache.cocoon.xml.XMLConsumer; 65 import org.apache.cocoon.xml.XMLUtils; 66 import org.apache.cocoon.xml.dom.DOMBuilder; 67 import org.apache.cocoon.xml.dom.DOMStreamer; 68 import org.apache.commons.jexl.Expression; 69 import org.apache.commons.jexl.ExpressionFactory; 70 import org.apache.commons.jexl.JexlContext; 71 import org.apache.commons.jexl.util.Introspector; 72 import org.apache.commons.jexl.util.introspection.Info; 73 import org.apache.commons.jexl.util.introspection.UberspectImpl; 74 import org.apache.commons.jexl.util.introspection.VelMethod; 75 import org.apache.commons.jexl.util.introspection.VelPropertyGet; 76 import org.apache.commons.jexl.util.introspection.VelPropertySet; 77 import org.apache.commons.jxpath.*; 78 import org.apache.commons.lang.ArrayUtils; 79 import org.apache.commons.lang.StringUtils; 80 import org.apache.excalibur.source.Source; 81 import org.apache.excalibur.source.SourceException; 82 import org.apache.excalibur.source.SourceValidity; 83 import org.apache.excalibur.xml.sax.XMLizable; 84 import org.mozilla.javascript.Context; 85 import org.mozilla.javascript.Function; 86 import org.mozilla.javascript.JavaScriptException; 87 import org.mozilla.javascript.NativeArray; 88 import org.mozilla.javascript.NativeJavaClass; 89 import org.mozilla.javascript.ScriptRuntime; 90 import org.mozilla.javascript.Scriptable; 91 import org.mozilla.javascript.ScriptableObject; 92 import org.mozilla.javascript.Undefined; 93 import org.mozilla.javascript.Wrapper; 94 import org.w3c.dom.Node ; 95 import org.w3c.dom.NodeList ; 96 import org.xml.sax.Attributes ; 97 import org.xml.sax.ContentHandler ; 98 import org.xml.sax.Locator ; 99 import org.xml.sax.SAXException ; 100 import org.xml.sax.ext.LexicalHandler ; 101 import org.xml.sax.helpers.AttributesImpl ; 102 103 116 public class JXTemplateGenerator extends ServiceableGenerator implements CacheableProcessingComponent { 117 118 private static final class JXTException extends LocatedRuntimeException { 120 JXTException(String message, Location loc, Throwable thr) { 121 super(message, thr, loc); 122 } 123 } 124 125 private static final JXPathContextFactory jxpathContextFactory = JXPathContextFactory.newInstance(); 126 127 private static final Attributes EMPTY_ATTRS = XMLUtils.EMPTY_ATTRIBUTES; 128 129 private final NamespacesTable namespaces = new NamespacesTable(); 130 131 private static final Iterator EMPTY_ITER = new Iterator () { 132 public boolean hasNext() { 133 return false; 134 } 135 136 public Object next() { 137 return null; 138 } 139 140 public void remove() { 141 } 143 }; 144 145 private static final Iterator NULL_ITER = new Iterator () { 146 public boolean hasNext() { 147 return true; 148 } 149 150 public Object next() { 151 return null; 152 } 153 154 public void remove() { 155 } 157 }; 158 159 private XMLConsumer getConsumer() { 160 return this.xmlConsumer; 161 } 162 163 public static class ErrorHolder extends Exception { 164 165 private Error err; 166 167 public ErrorHolder(Error err) { 168 super(err.getMessage()); 169 this.err = err; 170 } 171 172 public void printStackTrace(PrintStream ps) { 173 err.printStackTrace(ps); 174 } 175 176 public void printStackTrace(PrintWriter pw) { 177 err.printStackTrace(pw); 178 } 179 180 public void printStackTrace() { 181 err.printStackTrace(); 182 } 183 184 public Error getError() { 185 return err; 186 } 187 188 } 189 190 194 public static class LocationFacade implements Locator { 195 private Location locator; 196 197 public LocationFacade(Location initialLocation) { 198 this.locator = initialLocation; 199 } 200 201 public void setDocumentLocation(Location newLocation) { 202 this.locator = newLocation; 203 } 204 205 public int getColumnNumber() { 206 return this.locator.getColumnNumber(); 207 } 208 209 public int getLineNumber() { 210 return this.locator.getLineNumber(); 211 } 212 213 public String getPublicId() { 214 return null; 215 } 216 217 public String getSystemId() { 218 return this.locator.getURI(); 219 } 220 } 221 222 226 static class JSIntrospector extends UberspectImpl { 227 228 static class JSMethod implements VelMethod { 229 230 Scriptable scope; 231 String name; 232 233 public JSMethod(Scriptable scope, String name) { 234 this.scope = scope; 235 this.name = name; 236 } 237 238 public Object invoke(Object thisArg, Object [] args) throws Exception { 239 Context cx = Context.enter(); 240 try { 241 Object result; 242 Scriptable thisObj = !(thisArg instanceof Scriptable) ? 243 Context.toObject(thisArg, scope) : (Scriptable)thisArg; 244 result = ScriptableObject.getProperty(thisObj, name); 245 Object [] newArgs = null; 246 if (args != null) { 247 newArgs = new Object [args.length]; 248 int len = args.length; 249 for (int i = 0; i < len; i++) { 250 newArgs[i] = args[i]; 251 if (args[i] != null && 252 !(args[i] instanceof Number ) && 253 !(args[i] instanceof Boolean ) && 254 !(args[i] instanceof String ) && 255 !(args[i] instanceof Scriptable)) { 256 newArgs[i] = Context.toObject(args[i], scope); 257 } 258 } 259 } 260 result = ScriptRuntime.call(cx, result, thisObj, newArgs, scope); 261 if (result == Undefined.instance || result == Scriptable.NOT_FOUND) { 262 result = null; 263 } else if (!(result instanceof NativeJavaClass)) { 264 while (result instanceof Wrapper) { 265 result = ((Wrapper)result).unwrap(); 266 } 267 } 268 return result; 269 } catch (JavaScriptException e) { 270 throw new java.lang.reflect.InvocationTargetException (e); 271 } finally { 272 Context.exit(); 273 } 274 } 275 276 public boolean isCacheable() { 277 return false; 278 } 279 280 public String getMethodName() { 281 return name; 282 } 283 284 public Class getReturnType() { 285 return Object .class; 286 } 287 288 } 289 290 static class JSPropertyGet implements VelPropertyGet { 291 292 Scriptable scope; 293 String name; 294 295 public JSPropertyGet(Scriptable scope, String name) { 296 this.scope = scope; 297 this.name = name; 298 } 299 300 public Object invoke(Object thisArg) throws Exception { 301 Context cx = Context.enter(); 302 try { 303 Scriptable thisObj = !(thisArg instanceof Scriptable) ? 304 Context.toObject(thisArg, scope) : (Scriptable)thisArg; 305 Object result = ScriptableObject.getProperty(thisObj, name); 306 if (result == Scriptable.NOT_FOUND) { 307 result = ScriptableObject.getProperty(thisObj, "get" + StringUtils.capitalize(name)); 308 if (result != Scriptable.NOT_FOUND && result instanceof Function) { 309 try { 310 result = ((Function)result).call( 311 cx, ScriptableObject.getTopLevelScope(thisObj), thisObj, new Object [] {}); 312 } catch (JavaScriptException exc) { 313 exc.printStackTrace(); 314 result = null; 315 } 316 } 317 } 318 if (result == Scriptable.NOT_FOUND || result == Undefined.instance) { 319 result = null; 320 } else if (result instanceof Wrapper && !(result instanceof NativeJavaClass)) { 321 result = ((Wrapper)result).unwrap(); 322 } 323 return result; 324 } finally { 325 Context.exit(); 326 } 327 } 328 329 public boolean isCacheable() { 330 return false; 331 } 332 333 public String getMethodName() { 334 return name; 335 } 336 } 337 338 static class JSPropertySet implements VelPropertySet { 339 340 Scriptable scope; 341 String name; 342 343 public JSPropertySet(Scriptable scope, String name) { 344 this.scope = scope; 345 this.name = name; 346 } 347 348 public Object invoke(Object thisArg, Object rhs) throws Exception { 349 Context.enter(); 350 try { 351 Scriptable thisObj; 352 Object arg = rhs; 353 if (!(thisArg instanceof Scriptable)) { 354 thisObj = Context.toObject(thisArg, scope); 355 } else { 356 thisObj = (Scriptable)thisArg; 357 } 358 if (arg != null && 359 !(arg instanceof Number ) && 360 !(arg instanceof Boolean ) && 361 !(arg instanceof String ) && 362 !(arg instanceof Scriptable)) { 363 arg = Context.toObject(arg, scope); 364 } 365 ScriptableObject.putProperty(thisObj, name, arg); 366 return rhs; 367 } finally { 368 Context.exit(); 369 } 370 } 371 372 public boolean isCacheable() { 373 return false; 374 } 375 376 public String getMethodName() { 377 return name; 378 } 379 } 380 381 static class NativeArrayIterator implements Iterator { 382 383 NativeArray arr; 384 int index; 385 386 public NativeArrayIterator(NativeArray arr) { 387 this.arr = arr; 388 this.index = 0; 389 } 390 391 public boolean hasNext() { 392 return index < (int)arr.jsGet_length(); 393 } 394 395 public Object next() { 396 Context.enter(); 397 try { 398 Object result = arr.get(index++, arr); 399 if (result == Undefined.instance || 400 result == Scriptable.NOT_FOUND) { 401 result = null; 402 } else { 403 if (!(result instanceof NativeJavaClass)) { 404 while (result instanceof Wrapper) { 405 result = ((Wrapper)result).unwrap(); 406 } 407 } 408 } 409 return result; 410 } finally { 411 Context.exit(); 412 } 413 } 414 415 public void remove() { 416 arr.delete(index); 417 } 418 } 419 420 static class ScriptableIterator implements Iterator { 421 422 Scriptable scope; 423 Object [] ids; 424 int index; 425 426 public ScriptableIterator(Scriptable scope) { 427 this.scope = scope; 428 this.ids = scope.getIds(); 429 this.index = 0; 430 } 431 432 public boolean hasNext() { 433 return index < ids.length; 434 } 435 436 public Object next() { 437 Context.enter(); 438 try { 439 Object result = ScriptableObject.getProperty(scope, ids[index++].toString()); 440 if (result == Undefined.instance || result == Scriptable.NOT_FOUND) { 441 result = null; 442 } else if (!(result instanceof NativeJavaClass)) { 443 while (result instanceof Wrapper) { 444 result = ((Wrapper)result).unwrap(); 445 } 446 } 447 return result; 448 } finally { 449 Context.exit(); 450 } 451 } 452 453 public void remove() { 454 Context.enter(); 455 try { 456 scope.delete(ids[index].toString()); 457 } finally { 458 Context.exit(); 459 } 460 } 461 } 462 463 public Iterator getIterator(Object obj, Info i) throws Exception { 464 if (!(obj instanceof Scriptable)) { 465 if (obj instanceof Enumeration ) { 467 final Enumeration e = (Enumeration )obj; 468 return new Iterator () { 469 470 public boolean hasNext() { 471 return e.hasMoreElements(); 472 } 473 474 public Object next() { 475 return e.nextElement(); 476 } 477 478 public void remove() { 479 } 481 482 }; 483 } 484 if (obj instanceof Iterator ) { 485 return (Iterator )obj; 487 } 488 return super.getIterator(obj, i); 489 } 490 if (obj instanceof NativeArray) { 491 return new NativeArrayIterator((NativeArray)obj); 492 } 493 return new ScriptableIterator((Scriptable)obj); 494 } 495 496 public VelMethod getMethod(Object obj, String methodName, Object [] args, Info i) throws Exception { 497 return !(obj instanceof Scriptable) ? 498 super.getMethod(obj, methodName, args, i) : new JSMethod((Scriptable)obj, methodName); 499 } 500 501 public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i) throws Exception { 502 return !(obj instanceof Scriptable) ? 503 super.getPropertyGet(obj, identifier, i) : new JSPropertyGet((Scriptable)obj, identifier); 504 } 505 506 public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, Info i) throws Exception { 507 return !(obj instanceof Scriptable) ? 508 super.getPropertySet(obj, identifier, arg, i) : new JSPropertySet((Scriptable)obj, identifier); 509 } 510 } 511 512 static class MyJexlContext extends HashMap implements JexlContext { 513 514 private MyJexlContext closure; 515 516 MyJexlContext() { 517 this(null); 518 } 519 520 MyJexlContext(MyJexlContext closure) { 521 this.closure = closure; 522 } 523 524 public Map getVars() { 525 return this; 526 } 527 528 public void setVars(Map map) { 529 putAll(map); 530 } 531 532 public boolean containsKey(Object key) { 533 return this.get(key) !=null; 534 } 535 536 public Object get(Object key) { 537 if (key.equals("this")) { 538 return this; 539 } 540 Object result = super.get(key); 541 if (result == null && closure != null) { 542 result = closure.get(key); 543 } 544 return result; 545 } 546 } 547 548 static class MyVariables implements Variables { 549 550 MyVariables closure; 551 552 Map localVariables = new HashMap (); 553 554 static final String [] VARIABLES = new String [] { 555 "cocoon", 556 "continuation", 557 "flowContext", 558 "request", 559 "response", 560 "context", 561 "session", 562 "parameters" 563 }; 564 565 Object cocoon; 566 567 Object bean, kont, request, response, 569 session, context, parameters; 570 571 MyVariables(Object cocoon, 572 Object bean, 573 WebContinuation kont, 574 Object request, 575 Object session, 576 Object context, 577 Object parameters) { 578 this.cocoon = cocoon; 579 this.bean = bean; 580 this.kont = kont; 581 this.request = request; 582 this.session = session; 583 this.context = context; 584 this.parameters = parameters; 585 } 586 587 public MyVariables(MyVariables parent) { 588 this.closure = parent; 589 } 590 591 public boolean isDeclaredVariable(String varName) { 592 int len = VARIABLES.length; 593 for (int i = 0; i < len; i++) { 594 if (varName.equals(VARIABLES[i])) { 595 return true; 596 } 597 } 598 if (localVariables.containsKey(varName)) { 599 return true; 600 } 601 if (closure != null) { 602 return closure.isDeclaredVariable(varName); 603 } 604 return false; 605 } 606 607 public Object getVariable(String varName) { 608 Object result = localVariables.get(varName); 609 if (result != null) { 610 return result; 611 } 612 if (closure != null) { 613 return closure.getVariable(varName); 614 } 615 if (varName.equals("cocoon")) { 616 return cocoon; 617 } 618 if (varName.equals("continuation")) { 620 return kont; 621 } else if (varName.equals("flowContext")) { 622 return bean; 623 } else if (varName.equals("request")) { 624 return request; 625 } else if (varName.equals("session")) { 626 return session; 627 } else if (varName.equals("context")) { 628 return context; 629 } else if (varName.equals("parameters")) { 630 return parameters; 631 } 632 return null; 633 } 634 635 public void declareVariable(String varName, Object value) { 636 localVariables.put(varName, value); 637 } 638 639 public void undeclareVariable(String varName) { 640 localVariables.remove(varName); 641 } 642 } 643 644 static { 645 try { 647 Field field = Introspector.class.getDeclaredField("uberSpect"); 648 field.setAccessible(true); 649 field.set(null, new JSIntrospector()); 650 } catch (Exception e) { 651 e.printStackTrace(); 652 } 653 } 654 655 656 657 public final static String NS = "http://apache.org/cocoon/templates/jx/1.0"; 658 659 final static String TEMPLATE = "template"; 660 final static String FOR_EACH = "forEach"; 661 final static String IF = "if"; 662 final static String CHOOSE = "choose"; 663 final static String WHEN = "when"; 664 final static String OTHERWISE = "otherwise"; 665 final static String OUT = "out"; 666 final static String IMPORT = "import"; 667 final static String<
|