1 16 package org.apache.cocoon.components.flow.javascript.fom; 17 18 import java.beans.IntrospectionException ; 19 import java.beans.Introspector ; 20 import java.beans.PropertyDescriptor ; 21 import java.io.OutputStream ; 22 import java.util.ArrayList ; 23 import java.util.Arrays ; 24 import java.util.Collections ; 25 import java.util.Enumeration ; 26 import java.util.HashMap ; 27 import java.util.HashSet ; 28 import java.util.List ; 29 import java.util.Map ; 30 import java.util.Set ; 31 32 import org.apache.avalon.framework.CascadingRuntimeException; 33 import org.apache.avalon.framework.component.WrapperComponentManager; 34 import org.apache.avalon.framework.context.Context; 35 import org.apache.avalon.framework.context.ContextException; 36 import org.apache.avalon.framework.logger.Logger; 37 import org.apache.avalon.framework.service.ServiceManager; 38 import org.apache.cocoon.components.ContextHelper; 39 import org.apache.cocoon.components.LifecycleHelper; 40 import org.apache.cocoon.components.flow.ContinuationsManager; 41 import org.apache.cocoon.components.flow.WebContinuation; 42 import org.apache.cocoon.components.flow.Interpreter.Argument; 43 import org.apache.cocoon.environment.ObjectModelHelper; 44 import org.apache.cocoon.environment.Redirector; 45 import org.apache.cocoon.environment.Request; 46 import org.apache.cocoon.environment.Response; 47 import org.apache.cocoon.environment.Session; 48 import org.apache.cocoon.util.ClassUtils; 49 import org.mozilla.javascript.JavaScriptException; 50 import org.mozilla.javascript.NativeJavaClass; 51 import org.mozilla.javascript.NativeJavaObject; 52 import org.mozilla.javascript.Script; 53 import org.mozilla.javascript.Scriptable; 54 import org.mozilla.javascript.ScriptableObject; 55 import org.mozilla.javascript.Undefined; 56 import org.mozilla.javascript.Wrapper; 57 import org.mozilla.javascript.continuations.Continuation; 58 59 67 public class FOM_Cocoon extends ScriptableObject { 68 69 class CallContext { 70 CallContext caller; 71 Context avalonContext; 72 ServiceManager serviceManager; 73 FOM_JavaScriptInterpreter interpreter; 74 Redirector redirector; 75 Logger logger; 76 Scriptable request; 77 Scriptable response; 78 Scriptable session; 79 Scriptable context; 80 Scriptable parameters; 81 Scriptable log; 82 WebContinuation lastContinuation; 83 FOM_WebContinuation fwk; 84 PageLocalScopeImpl currentPageLocal; 85 86 public CallContext(CallContext caller, 87 FOM_JavaScriptInterpreter interp, 88 Redirector redirector, 89 ServiceManager manager, 90 Context avalonContext, 91 Logger logger, 92 WebContinuation lastContinuation) { 93 this.caller = caller; 94 this.interpreter = interp; 95 this.redirector = redirector; 96 this.serviceManager = manager; 97 this.avalonContext = avalonContext; 98 this.logger = logger; 99 this.lastContinuation = lastContinuation; 100 if (lastContinuation != null) { 101 fwk = new FOM_WebContinuation(lastContinuation); 102 Scriptable scope = FOM_Cocoon.this.getParentScope(); 103 fwk.setParentScope(scope); 104 fwk.setPrototype(getClassPrototype(scope, fwk.getClassName())); 105 this.currentPageLocal = fwk.getPageLocal(); 106 } 107 if (this.currentPageLocal != null) { 108 this.currentPageLocal = this.currentPageLocal.duplicate(); 110 } else { 111 this.currentPageLocal = new PageLocalScopeImpl(getTopLevelScope(FOM_Cocoon.this)); 112 } 113 pageLocal.setDelegate(this.currentPageLocal); 114 } 115 116 public FOM_WebContinuation getLastContinuation() { 117 return fwk; 118 } 119 120 public void setLastContinuation(FOM_WebContinuation fwk) { 121 this.fwk = fwk; 122 if (fwk != null) { 123 pageLocal.setDelegate(fwk.getPageLocal()); 124 this.lastContinuation = fwk.getWebContinuation(); 125 } else { 126 this.lastContinuation = null; 127 } 128 } 129 130 public Scriptable getSession() { 131 if (session != null) { 132 return session; 133 } 134 Map objectModel = ContextHelper.getObjectModel(this.avalonContext); 135 session = new FOM_Session( 136 getParentScope(), 137 ObjectModelHelper.getRequest(objectModel).getSession(true)); 138 return session; 139 } 140 141 public Scriptable getRequest() { 142 if (request != null) { 143 return request; 144 } 145 Map objectModel = ContextHelper.getObjectModel(this.avalonContext); 146 request = new FOM_Request( 147 getParentScope(), 148 ObjectModelHelper.getRequest(objectModel)); 149 return request; 150 } 151 152 public Scriptable getContext() { 153 if (context != null) { 154 return context; 155 } 156 Map objectModel = ContextHelper.getObjectModel(this.avalonContext); 157 context = new FOM_Context( 158 getParentScope(), 159 ObjectModelHelper.getContext(objectModel)); 160 return context; 161 } 162 163 public Scriptable getResponse() { 164 if (response != null) { 165 return response; 166 } 167 Map objectModel = ContextHelper.getObjectModel(this.avalonContext); 168 response = org.mozilla.javascript.Context.toObject( 169 ObjectModelHelper.getResponse(objectModel), 170 getParentScope()); 171 return response; 172 } 173 174 public Scriptable getLog() { 175 if (log != null) { 176 return log; 177 } 178 log = org.mozilla.javascript.Context.toObject(logger, getParentScope()); 179 return log; 180 } 181 182 public Scriptable getParameters() { 183 return parameters; 184 } 185 186 public void setParameters(Scriptable parameters) { 187 this.parameters = parameters; 188 } 189 } 190 191 private CallContext currentCall; 192 protected PageLocalScopeHolder pageLocal; 193 194 public String getClassName() { 195 return "FOM_Cocoon"; 196 } 197 198 199 static void init(Scriptable scope) throws Exception { 201 defineClass(scope, FOM_Cocoon.class); 203 defineClass(scope, FOM_WebContinuation.class); 210 defineClass(scope, PageLocalImpl.class); 211 } 212 213 void pushCallContext(FOM_JavaScriptInterpreter interp, 214 Redirector redirector, 215 ServiceManager manager, 216 Context avalonContext, 217 Logger logger, 218 WebContinuation lastContinuation) { 219 if (pageLocal == null) { 220 pageLocal = new PageLocalScopeHolder(getTopLevelScope(this)); 221 } 222 223 ServiceManager sitemapManager; 225 try { 226 sitemapManager = (ServiceManager)avalonContext.get(ContextHelper.CONTEXT_SITEMAP_SERVICE_MANAGER); 227 } catch (ContextException e) { 228 throw new CascadingRuntimeException("Cannot get sitemap service manager", e); 229 } 230 231 this.currentCall = new CallContext(currentCall, interp, redirector, sitemapManager, 232 avalonContext, 233 logger, lastContinuation); 234 } 235 236 void popCallContext() { 237 FOM_JavaScriptFlowHelper.setFOM_FlowScope(this.getObjectModel(), null); 239 240 this.currentCall = this.currentCall.caller; 241 if (this.currentCall != null) { 243 pageLocal.setDelegate(this.currentCall.currentPageLocal); 244 } else { 245 pageLocal.setDelegate(null); 246 } 247 } 248 249 250 public FOM_WebContinuation jsGet_continuation() { 251 return currentCall.getLastContinuation(); 253 } 254 255 public void jsSet_continuation(Object obj) { 256 FOM_WebContinuation fwk = (FOM_WebContinuation)unwrap(obj); 257 currentCall.setLastContinuation(fwk); 258 } 259 260 public FOM_WebContinuation jsFunction_sendPage(String uri, 261 Object obj, 262 Object wk) 263 throws Exception { 264 FOM_WebContinuation fom_wk = (FOM_WebContinuation)unwrap(wk); 265 if (fom_wk != null) { 266 fom_wk.setPageLocal(pageLocal.getDelegate()); 268 } 269 forwardTo(uri, unwrap(obj), fom_wk); 270 return fom_wk; 271 } 272 273 public Scriptable jsFunction_createPageLocal() { 274 return pageLocal.createPageLocal(); 275 } 276 277 public void jsFunction_processPipelineTo(String uri, 278 Object map, 279 Object outputStream) 280 throws Exception { 281 Object out = unwrap(outputStream); 282 if (!(out instanceof OutputStream )) { 283 throw new JavaScriptException("expected a java.io.OutputStream instead of " + out); 284 } 285 getInterpreter().process(getParentScope(), this, uri, map, 286 (OutputStream )out); 287 } 288 289 public void jsFunction_redirectTo(String uri, boolean isGlobal) throws Exception { 290 if (isGlobal) { 291 this.currentCall.redirector.globalRedirect(false, uri); 292 } else { 293 this.currentCall.redirector.redirect(false, uri); 294 } 295 } 296 297 public void jsFunction_sendStatus(int sc) { 298 this.currentCall.redirector.sendStatus(sc); 299 } 300 301 319 320 326 public Object jsFunction_getComponent(String id) 327 throws Exception { 328 return getServiceManager().lookup(id); 329 } 330 331 336 public void jsFunction_releaseComponent( Object component ) throws Exception { 337 this.getServiceManager().release( unwrap(component) ); 338 } 339 340 347 public Object jsFunction_load( String filename ) 348 throws Exception { 349 org.mozilla.javascript.Context cx = 350 org.mozilla.javascript.Context.getCurrentContext(); 351 Scriptable scope = getParentScope(); 352 Script script = getInterpreter().compileScript(cx, filename); 353 return script.exec( cx, scope ); 354 } 355 356 372 public Object jsFunction_setupObject(Object obj) throws Exception { 373 LifecycleHelper.setupComponent( 374 unwrap(obj), 375 this.getLogger(), 376 this.getAvalonContext(), 377 this.getServiceManager(), 378 new WrapperComponentManager(this.getServiceManager()), 379 null, null, true); 382 return obj; 383 } 384 385 401 public Object jsFunction_createObject(Object classObj) throws Exception { 402 Object result; 403 404 if (classObj instanceof String ) { 405 result = ClassUtils.newInstance((String )classObj); 406 407 } else if (classObj instanceof NativeJavaClass) { 408 Class clazz = ((NativeJavaClass)classObj).getClassObject(); 409 result = clazz.newInstance(); 410 411 } else { 412 throw new IllegalArgumentException ("cocoon.createObject expects either a String or Class argument, but got " 413 + classObj.getClass()); 414 } 415 416 return jsFunction_setupObject(result); 417 } 418 419 425 public void jsFunction_disposeObject(Object obj) throws Exception { 426 LifecycleHelper.decommission(obj); 427 } 428 429 435 private static abstract class AttributeHolderJavaObject extends NativeJavaObject { 436 437 private static Map classProps = new HashMap (); 438 private Set propNames; 439 440 public AttributeHolderJavaObject(Scriptable scope, Object object, Class clazz) { 441 super(scope, object, clazz); 442 this.propNames = getProperties(object.getClass()); 443 } 444 445 446 private static Set getProperties(Class clazz) { 447 Set result = (Set )classProps.get(clazz); 448 if (result == null) { 449 try { 450 PropertyDescriptor [] descriptors = Introspector.getBeanInfo(clazz).getPropertyDescriptors(); 451 result = new HashSet (); 452 for (int i = 0; i < descriptors.length; i++) { 453 result.add(descriptors[i].getName()); 454 } 455 } catch (IntrospectionException e) { 456 result = Collections.EMPTY_SET; 458 } 459 classProps.put(clazz, result); 460 } 461 return result; 462 } 463 464 465 protected abstract Enumeration getAttributeNames(); 466 protected abstract Object getAttribute(String name); 467 468 public Object [] getIds() { 469 Object [] classIds = super.getIds(); 471 472 ArrayList idList = new ArrayList (Arrays.asList(classIds)); 474 Enumeration iter = getAttributeNames(); 475 while(iter.hasMoreElements()) { 476 idList.add(iter.nextElement()); 477 } 478 return idList.toArray(); 479 } 480 481 public boolean has(String name, Scriptable start) { 482 return super.has(name, start) || getAttribute(name) != null; 483 } 484 485 public Object get(String name, Scriptable start) { 486 Object result; 487 if (this.propNames.contains(name)) { 489 result = NOT_FOUND; 490 } else { 491 result = super.get(name, start); 492 } 493 if (result == NOT_FOUND) { 494 result = getAttribute(name); 495 if (result != null) { 496 result = wrap(start, result, null); 497 } else { 498 result = NOT_FOUND; 499 } 500 } 501 return result; 502 } 503 } 504 505 512 public static class FOM_Request extends AttributeHolderJavaObject { 513 private final Request request; 514 515 public FOM_Request(Scriptable scope, Request request) { 516 super(scope, request, Request.class); 517 this.request = request; 518 } 519 520 protected Enumeration getAttributeNames() { 521 return this.request.getParameterNames(); 522 } 523 524 protected Object getAttribute(String name) { 525 return this.request.getParameter(name); 526 } 527 } 528 529 534 public static class FOM_Session extends AttributeHolderJavaObject { 535 private final Session session; 536 537 public FOM_Session(Scriptable scope, Session session) { 538 super(scope, session, Session.class); 539 this.session = session; 540 } 541 542 protected Enumeration getAttributeNames() { 543 return this.session.getAttributeNames(); 544 } 545 546 protected Object getAttribute(String name) { 547 return this.session.getAttribute(name); 548 } 549 } 550 551 556 public static class FOM_Context extends AttributeHolderJavaObject { 557 private final org.apache.cocoon.environment.Context context; 558 559 public FOM_Context(Scriptable scope, org.apache.cocoon.environment.Context context) { 560 super(scope, context, org.apache.cocoon.environment.Context.class); 561 this.context = context; 562 } 563 564 protected Enumeration getAttributeNames() { 565 return this.context.getAttributeNames(); 566 } 567 568 protected Object getAttribute(String name) { 569 return this.context.getAttribute(name); 570 } 571 } 572 573 public Scriptable jsGet_request() { 574 return currentCall.getRequest(); 575 } 576 577 public Scriptable jsGet_response() { 578 return currentCall.getResponse(); 579 } 580 581 public Scriptable jsGet_log() { 582 return currentCall.getLog(); 583 } 584 585 public Scriptable jsGet_context() { 586 return currentCall.getContext(); 587 } 588 589 public Scriptable jsGet_session() { 590 return currentCall.getSession(); 591 } 592 593 599 public Scriptable jsGet_parameters() { 600 return getParameters(); 601 } 602 603 public Scriptable getParameters() { 604 return currentCall.getParameters(); 605 } 606 607 void setParameters(Scriptable value) { 608 currentCall.setParameters(value); 609 } 610 611 private static Object unwrap(Object obj) { 613 if (obj instanceof Wrapper) { 614 obj = ((Wrapper)obj).unwrap(); 615 } else if (obj == Undefined.instance) { 616 obj = null; 617 } 618 return obj; 619 } 620 621 623 627 public Request getRequest() { 628 return ObjectModelHelper.getRequest(ContextHelper.getObjectModel(currentCall.avalonContext)); 629 } 630 631 635 public Session getSession() { 636 return ObjectModelHelper.getRequest(ContextHelper.getObjectModel(currentCall.avalonContext)).getSession(true); 637 } 638 639 643 public Response getResponse() { 644 return ObjectModelHelper.getResponse(ContextHelper.getObjectModel(currentCall.avalonContext)); 645 } 646 647 651 public org.apache.cocoon.environment.Context getContext() { 652 return ObjectModelHelper.getContext(ContextHelper.getObjectModel(currentCall.avalonContext)); 653 } 654 655 659 public Map getObjectModel() { 660 return ContextHelper.getObjectModel(currentCall.avalonContext); 661 } 662 663 private Context getAvalonContext() { 664 return currentCall.avalonContext; 665 } 666 667 private Logger getLogger() { 668 return currentCall.logger; 669 } 670 671 public ServiceManager getServiceManager() { 672 return currentCall.serviceManager; 673 } 674 675 private FOM_JavaScriptInterpreter getInterpreter() { 676 return currentCall.interpreter; 677 } 678 679 683 public String getInterpreterId() { 684 return getInterpreter().getInterpreterID(); 685 } 686 687 693 694 public void forwardTo(String uri, 695 Object bean, 696 FOM_WebContinuation fom_wk) 697 throws Exception { 698 getInterpreter().forwardTo(getTopLevelScope(this), 699 this, 700 uri, 701 bean, 702 fom_wk, 703 this.currentCall.redirector); 704 } 705 706 715 public void handleContinuation(String kontId, Scriptable parameters) 716 throws Exception { 717 List list = null; 718 if (parameters == null || parameters == Undefined.instance) { 719 parameters = getParameters(); 720 } 721 Object [] ids = parameters.getIds(); 722 list = new ArrayList (); 723 for (int i = 0; i < ids.length; i++) { 724 String name = ids[i].toString(); 725 Argument arg = new Argument(name, 726 org.mozilla.javascript.Context.toString(getProperty(parameters, name))); 727 list.add(arg); 728 } 729 getInterpreter().handleContinuation(kontId, list, this.currentCall.redirector); 730 } 731 732 735 private FOM_WebContinuation findValidParent(FOM_WebContinuation wk) { 736 if (wk != null) { 737 WebContinuation wc = wk.getWebContinuation(); 738 while (wc != null && wc.disposed()) { 739 wc = wc.getParentContinuation(); 740 } 741 if (wc != null) { 742 return new FOM_WebContinuation(wc); 743 } 744 } 745 746 return null; 747 } 748 749 757 public FOM_WebContinuation jsFunction_makeWebContinuation(Object k, 758 Object ttl) 759 throws Exception { 760 double d = org.mozilla.javascript.Context.toNumber(ttl); 761 FOM_WebContinuation result = 762 makeWebContinuation((Continuation)unwrap(k), 763 findValidParent(jsGet_continuation()), 764 (int)d); 765 result.setPageLocal(pageLocal.getDelegate()); 766 currentCall.setLastContinuation(result); 767 return result; 768 } 769 770 776 public FOM_WebContinuation makeWebContinuation(Continuation k, 777 FOM_WebContinuation parent, 778 int timeToLive) 779 throws Exception { 780 if (k == null) { 781 return null; 782 } 783 WebContinuation wk; 784 ContinuationsManager contMgr; 785 contMgr = (ContinuationsManager) 786 getServiceManager().lookup(ContinuationsManager.ROLE); 787 wk = contMgr.createWebContinuation(unwrap(k), 788 (parent == null ? null : parent.getWebContinuation()), 789 timeToLive, 790 getInterpreter().getInterpreterID(), 791 null); 792 FOM_WebContinuation result = new FOM_WebContinuation(wk); 793 result.setParentScope(getParentScope()); 794 result.setPrototype(getClassPrototype(getParentScope(), 795 result.getClassName())); 796 return result; 797 } 798 } 799 | Popular Tags |