Source Code Cross Referenced for FOM_JavaScriptInterpreter.java in  » Content-Management-System » apache-lenya-2.0 » org » apache » cocoon » components » flow » javascript » fom » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Content Management System » apache lenya 2.0 » org.apache.cocoon.components.flow.javascript.fom 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one or more
003:         * contributor license agreements.  See the NOTICE file distributed with
004:         * this work for additional information regarding copyright ownership.
005:         * The ASF licenses this file to You under the Apache License, Version 2.0
006:         * (the "License"); you may not use this file except in compliance with
007:         * the License.  You may obtain a copy of the License at
008:         *
009:         *      http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         */
017:        package org.apache.cocoon.components.flow.javascript.fom;
018:
019:        import org.apache.avalon.framework.activity.Initializable;
020:        import org.apache.avalon.framework.configuration.Configuration;
021:        import org.apache.avalon.framework.configuration.ConfigurationException;
022:        import org.apache.avalon.framework.service.ServiceManager;
023:
024:        import org.apache.cocoon.ResourceNotFoundException;
025:        import org.apache.cocoon.components.ContextHelper;
026:        import org.apache.cocoon.components.flow.CompilingInterpreter;
027:        import org.apache.cocoon.components.flow.Interpreter;
028:        import org.apache.cocoon.components.flow.InvalidContinuationException;
029:        import org.apache.cocoon.components.flow.WebContinuation;
030:        import org.apache.cocoon.components.flow.javascript.JSErrorReporter;
031:        import org.apache.cocoon.components.flow.javascript.LocationTrackingDebugger;
032:        import org.apache.cocoon.components.flow.javascript.ScriptablePointerFactory;
033:        import org.apache.cocoon.components.flow.javascript.ScriptablePropertyHandler;
034:        import org.apache.cocoon.environment.ObjectModelHelper;
035:        import org.apache.cocoon.environment.Redirector;
036:        import org.apache.cocoon.environment.Request;
037:        import org.apache.cocoon.environment.Session;
038:
039:        import org.apache.commons.jxpath.JXPathIntrospector;
040:        import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl;
041:        import org.apache.excalibur.source.Source;
042:        import org.apache.excalibur.source.SourceResolver;
043:        import org.apache.excalibur.source.SourceValidity;
044:        import org.apache.regexp.RE;
045:        import org.apache.regexp.RECompiler;
046:        import org.apache.regexp.REProgram;
047:        import org.mozilla.javascript.BaseFunction;
048:        import org.mozilla.javascript.Context;
049:        import org.mozilla.javascript.EcmaError;
050:        import org.mozilla.javascript.Function;
051:        import org.mozilla.javascript.JavaScriptException;
052:        import org.mozilla.javascript.NativeJavaClass;
053:        import org.mozilla.javascript.NativeJavaPackage;
054:        import org.mozilla.javascript.Script;
055:        import org.mozilla.javascript.ScriptRuntime;
056:        import org.mozilla.javascript.Scriptable;
057:        import org.mozilla.javascript.ScriptableObject;
058:        import org.mozilla.javascript.WrappedException;
059:        import org.mozilla.javascript.continuations.Continuation;
060:        import org.mozilla.javascript.tools.debugger.Main;
061:        import org.mozilla.javascript.tools.shell.Global;
062:
063:        import java.awt.Dimension;
064:        import java.awt.Toolkit;
065:        import java.io.BufferedReader;
066:        import java.io.IOException;
067:        import java.io.InputStreamReader;
068:        import java.io.OutputStream;
069:        import java.io.PushbackInputStream;
070:        import java.io.Reader;
071:        import java.io.StringReader;
072:        import java.util.ArrayList;
073:        import java.util.HashMap;
074:        import java.util.HashSet;
075:        import java.util.Iterator;
076:        import java.util.LinkedList;
077:        import java.util.List;
078:        import java.util.Map;
079:        import java.util.Set;
080:        import java.util.StringTokenizer;
081:
082:        /**
083:         * Interface with the JavaScript interpreter.
084:         *
085:         * @author <a href="mailto:ovidiu@apache.org">Ovidiu Predescu</a>
086:         * @author <a href="mailto:crafterm@apache.org">Marcus Crafter</a>
087:         * @since March 25, 2002
088:         * @version CVS $Id: FOM_JavaScriptInterpreter.java 494773 2007-01-10 09:24:02Z cziegeler $
089:         */
090:        public class FOM_JavaScriptInterpreter extends CompilingInterpreter
091:                implements  Initializable {
092:
093:            /**
094:             * A long value is stored under this key in each top level JavaScript
095:             * thread scope object. When you enter a context any scripts whose
096:             * modification time is later than this value will be recompiled and reexecuted,
097:             * and this value will be updated to the current time.
098:             */
099:            private final static String LAST_EXEC_TIME = "__PRIVATE_LAST_EXEC_TIME__";
100:
101:            /**
102:             * Prefix for session/request attribute storing JavaScript global scope object.
103:             */
104:            private static final String USER_GLOBAL_SCOPE = "FOM JavaScript GLOBAL SCOPE/";
105:
106:            /**
107:             * This is the only optimization level that supports continuations
108:             * in the Christoper Oliver's Rhino JavaScript implementation
109:             */
110:            private static final int OPTIMIZATION_LEVEL = -2;
111:
112:            /**
113:             * When was the last time we checked for script modifications. Used
114:             * only if {@link #reloadScripts} is true.
115:             */
116:            private long lastTimeCheck;
117:
118:            /**
119:             * Shared global scope for scripts and other immutable objects
120:             */
121:            private Global scope;
122:
123:            // FIXME: Does not belong here, should be moved into the sitemap or even higher?
124:            private CompilingClassLoader classLoader;
125:            private MyClassRepository javaClassRepository = new MyClassRepository();
126:            private String[] javaSourcePath;
127:
128:            /**
129:             * List of <code>String</code> objects that represent files to be
130:             * read in by the JavaScript interpreter.
131:             */
132:            private List topLevelScripts = new ArrayList();
133:
134:            private JSErrorReporter errorReporter;
135:            private boolean enableDebugger;
136:
137:            /**
138:             * Needed to get things working with JDK 1.3. Can be removed once we
139:             * don't support that platform any more.
140:             */
141:            protected ServiceManager getServiceManager() {
142:                return manager;
143:            }
144:
145:            class MyClassRepository implements 
146:                    CompilingClassLoader.ClassRepository {
147:                Map javaSource = new HashMap();
148:                Map javaClass = new HashMap();
149:                Map sourceToClass = new HashMap();
150:                Map classToSource = new HashMap();
151:
152:                public synchronized void addCompiledClass(String className,
153:                        Source src, byte[] contents) {
154:                    javaSource.put(src.getURI(), src.getValidity());
155:                    javaClass.put(className, contents);
156:                    String uri = src.getURI();
157:                    Set set = (Set) sourceToClass.get(uri);
158:                    if (set == null) {
159:                        set = new HashSet();
160:                        sourceToClass.put(uri, set);
161:                    }
162:                    set.add(className);
163:                    classToSource.put(className, src.getURI());
164:                }
165:
166:                public synchronized byte[] getCompiledClass(String className) {
167:                    return (byte[]) javaClass.get(className);
168:                }
169:
170:                public synchronized boolean upToDateCheck() throws Exception {
171:                    SourceResolver sourceResolver = (SourceResolver) getServiceManager()
172:                            .lookup(SourceResolver.ROLE);
173:                    try {
174:                        List invalid = new LinkedList();
175:                        for (Iterator i = javaSource.entrySet().iterator(); i
176:                                .hasNext();) {
177:                            Map.Entry e = (Map.Entry) i.next();
178:                            String uri = (String) e.getKey();
179:                            SourceValidity validity = (SourceValidity) e
180:                                    .getValue();
181:                            int valid = validity.isValid();
182:                            if (valid == SourceValidity.UNKNOWN) {
183:                                Source newSrc = null;
184:                                try {
185:                                    newSrc = sourceResolver.resolveURI(uri);
186:                                    valid = newSrc.getValidity().isValid(
187:                                            validity);
188:                                } catch (Exception ignored) {
189:                                    // ignore exception
190:                                } finally {
191:                                    if (newSrc != null) {
192:                                        sourceResolver.release(newSrc);
193:                                    }
194:                                }
195:                            }
196:                            if (valid != SourceValidity.VALID) {
197:                                invalid.add(uri);
198:                            }
199:                        }
200:
201:                        for (Iterator i = invalid.iterator(); i.hasNext();) {
202:                            String uri = (String) i.next();
203:                            Set set = (Set) sourceToClass.get(uri);
204:                            Iterator ii = set.iterator();
205:                            while (ii.hasNext()) {
206:                                String className = (String) ii.next();
207:                                sourceToClass.remove(className);
208:                                javaClass.remove(className);
209:                                classToSource.remove(className);
210:                            }
211:                            set.clear();
212:                            javaSource.remove(uri);
213:                        }
214:
215:                        return invalid.size() == 0;
216:                    } finally {
217:                        getServiceManager().release(sourceResolver);
218:                    }
219:                }
220:            }
221:
222:            /**
223:             * JavaScript debugger: there's only one of these: it can debug multiple
224:             * threads executing JS code.
225:             */
226:            private static Main debugger;
227:
228:            static synchronized Main getDebugger() {
229:                if (debugger == null) {
230:                    final Main db = new Main("Cocoon Flow Debugger");
231:                    db.pack();
232:                    Dimension size = Toolkit.getDefaultToolkit()
233:                            .getScreenSize();
234:                    size.width *= 0.75;
235:                    size.height *= 0.75;
236:                    db.setSize(size);
237:                    db.setExitAction(new Runnable() {
238:                        public void run() {
239:                            db.setVisible(false);
240:                        }
241:                    });
242:                    db.setOptimizationLevel(OPTIMIZATION_LEVEL);
243:                    db.setVisible(true);
244:                    debugger = db;
245:                    Context.addContextListener(debugger);
246:                }
247:                return debugger;
248:            }
249:
250:            public void configure(Configuration config)
251:                    throws ConfigurationException {
252:                super .configure(config);
253:
254:                String loadOnStartup = config.getChild("load-on-startup")
255:                        .getValue(null);
256:                if (loadOnStartup != null) {
257:                    register(loadOnStartup);
258:                }
259:
260:                String debugger = config.getChild("debugger").getValue(null);
261:                enableDebugger = "enabled".equalsIgnoreCase(debugger);
262:
263:                if (reloadScripts) {
264:                    String classPath = config.getChild("classpath").getValue(
265:                            null);
266:                    synchronized (javaClassRepository) {
267:                        if (classPath != null) {
268:                            StringTokenizer izer = new StringTokenizer(
269:                                    classPath, ";");
270:                            int i = 0;
271:                            javaSourcePath = new String[izer.countTokens() + 1];
272:                            javaSourcePath[javaSourcePath.length - 1] = "";
273:                            while (izer.hasMoreTokens()) {
274:                                javaSourcePath[i++] = izer.nextToken();
275:                            }
276:                        } else {
277:                            javaSourcePath = new String[] { "" };
278:                        }
279:                        updateSourcePath();
280:                    }
281:                }
282:            }
283:
284:            public void initialize() throws Exception {
285:                if (enableDebugger) {
286:                    if (getLogger().isDebugEnabled()) {
287:                        getLogger().debug("Flow debugger enabled, creating");
288:                    }
289:                    getDebugger().doBreak();
290:                }
291:                Context context = Context.enter();
292:                context.setOptimizationLevel(OPTIMIZATION_LEVEL);
293:                context.setCompileFunctionsWithDynamicScope(true);
294:                context.setGeneratingDebug(true);
295:                // add support for Rhino objects to JXPath
296:                JXPathIntrospector.registerDynamicClass(Scriptable.class,
297:                        ScriptablePropertyHandler.class);
298:                JXPathContextReferenceImpl
299:                        .addNodePointerFactory(new ScriptablePointerFactory());
300:
301:                try {
302:                    scope = new Global(context);
303:                    // Access to Cocoon internal objects
304:                    FOM_Cocoon.init(scope);
305:                    errorReporter = new JSErrorReporter(getLogger());
306:                } catch (Exception e) {
307:                    Context.exit();
308:                    e.printStackTrace();
309:                    throw e;
310:                }
311:            }
312:
313:            private ClassLoader getClassLoader(boolean needsRefresh)
314:                    throws Exception {
315:                if (!reloadScripts) {
316:                    return Thread.currentThread().getContextClassLoader();
317:                }
318:
319:                synchronized (javaClassRepository) {
320:                    boolean reload = needsRefresh || classLoader == null;
321:                    if (needsRefresh && classLoader != null) {
322:                        reload = !javaClassRepository.upToDateCheck();
323:                    }
324:
325:                    if (reload) {
326:                        // FIXME FIXME FIXME Resolver not released!
327:                        classLoader = new CompilingClassLoader(Thread
328:                                .currentThread().getContextClassLoader(),
329:                                (SourceResolver) manager
330:                                        .lookup(SourceResolver.ROLE),
331:                                javaClassRepository);
332:                        classLoader
333:                                .addSourceListener(new CompilingClassLoader.SourceListener() {
334:                                    public void sourceCompiled(Source src) {
335:                                        // no action
336:                                    }
337:
338:                                    public void sourceCompilationError(
339:                                            Source src, String msg) {
340:                                        if (src != null) {
341:                                            throw Context
342:                                                    .reportRuntimeError(msg);
343:                                        }
344:                                    }
345:                                });
346:                        updateSourcePath();
347:                    }
348:                    return classLoader;
349:                }
350:            }
351:
352:            private void updateSourcePath() {
353:                if (classLoader != null) {
354:                    classLoader.setSourcePath(javaSourcePath);
355:                }
356:            }
357:
358:            /**
359:             * Returns the JavaScript scope, a Scriptable object, from the user
360:             * session instance. Each interpreter instance can have a scope
361:             * associated with it.
362:             *
363:             * @return a <code>ThreadScope</code> value
364:             */
365:            private ThreadScope getSessionScope() throws Exception {
366:                final String scopeID = USER_GLOBAL_SCOPE + getInterpreterID();
367:                final Request request = ContextHelper
368:                        .getRequest(this .avalonContext);
369:
370:                ThreadScope scope = null;
371:
372:                // Get/create the scope attached to the current context
373:                Session session = request.getSession(false);
374:                if (session != null) {
375:                    scope = (ThreadScope) session.getAttribute(scopeID);
376:                } else {
377:                    scope = (ThreadScope) request.getAttribute(scopeID);
378:                }
379:
380:                if (scope == null) {
381:                    scope = createThreadScope();
382:                    // Save scope in the request early to allow recursive Flow calls
383:                    request.setAttribute(scopeID, scope);
384:                }
385:
386:                return scope;
387:            }
388:
389:            /**
390:             * Associates a JavaScript scope, a Scriptable object, with
391:             * {@link #getInterpreterID() identifier} of this {@link Interpreter}
392:             * instance.
393:             *
394:             * @param scope a <code>ThreadScope</code> value
395:             */
396:            private void setSessionScope(ThreadScope scope) throws Exception {
397:                if (scope.useSession) {
398:                    final String scopeID = USER_GLOBAL_SCOPE
399:                            + getInterpreterID();
400:                    final Request request = ContextHelper
401:                            .getRequest(this .avalonContext);
402:
403:                    // FIXME: Where "session scope" should go when session is invalidated?
404:                    // Attach the scope to the current context
405:                    try {
406:                        Session session = request.getSession(true);
407:                        session.setAttribute(scopeID, scope);
408:                    } catch (IllegalStateException e) {
409:                        // Session might be invalidated already.
410:                        if (getLogger().isDebugEnabled()) {
411:                            getLogger()
412:                                    .debug(
413:                                            "Got '"
414:                                                    + e
415:                                                    + "' while trying to set session scope.",
416:                                            e);
417:                        }
418:                    }
419:                }
420:            }
421:
422:            public static class ThreadScope extends ScriptableObject {
423:                private static final String[] BUILTIN_PACKAGES = { "javax",
424:                        "org", "com" };
425:
426:                private ClassLoader classLoader;
427:
428:                /* true if this scope has assigned any global vars */
429:                boolean useSession;
430:
431:                boolean locked = false;
432:
433:                /**
434:                 * Initializes new top-level scope.
435:                 */
436:                public ThreadScope(Global scope) throws Exception {
437:                    final Context context = Context.getCurrentContext();
438:
439:                    final String[] names = { "importClass" };
440:                    defineFunctionProperties(names, ThreadScope.class,
441:                            ScriptableObject.DONTENUM);
442:
443:                    setPrototype(scope);
444:
445:                    // We want this to be a new top-level scope, so set its
446:                    // parent scope to null. This means that any variables created
447:                    // by assignments will be properties of this.
448:                    setParentScope(null);
449:
450:                    // Put in the thread scope the Cocoon object, which gives access
451:                    // to the interpreter object, and some Cocoon objects. See
452:                    // FOM_Cocoon for more details.
453:                    final Object[] args = {};
454:                    FOM_Cocoon cocoon = (FOM_Cocoon) context.newObject(this ,
455:                            "FOM_Cocoon", args);
456:                    cocoon.setParentScope(this );
457:                    super .put("cocoon", this , cocoon);
458:
459:                    defineProperty(LAST_EXEC_TIME, new Long(0),
460:                            ScriptableObject.DONTENUM
461:                                    | ScriptableObject.PERMANENT);
462:                }
463:
464:                public String getClassName() {
465:                    return "ThreadScope";
466:                }
467:
468:                public void setLock(boolean lock) {
469:                    this .locked = lock;
470:                }
471:
472:                public void put(String name, Scriptable start, Object value) {
473:                    //Allow setting values to existing variables, or if this is a
474:                    //java class (used by importClass & importPackage)
475:                    if (this .locked && !has(name, start)
476:                            && !(value instanceof  NativeJavaClass)
477:                            && !(value instanceof  Function)) {
478:                        // Need to wrap into a runtime exception as Scriptable.put has no throws clause...
479:                        throw new WrappedException(
480:                                new JavaScriptException(
481:                                        "Implicit declaration of global variable '"
482:                                                + name
483:                                                + "' forbidden. Please ensure all variables are explicitely declared with the 'var' keyword"));
484:                    }
485:                    this .useSession = true;
486:                    super .put(name, start, value);
487:                }
488:
489:                public void put(int index, Scriptable start, Object value) {
490:                    // FIXME(SW): do indexed properties have a meaning on the global scope?
491:                    if (this .locked && !has(index, start)) {
492:                        throw new WrappedException(new JavaScriptException(
493:                                "Global scope locked. Cannot set value for index "
494:                                        + index));
495:                    }
496:                    this .useSession = true;
497:                    super .put(index, start, value);
498:                }
499:
500:                // Invoked after script execution
501:                void onExec() {
502:                    this .useSession = false;
503:                    super .put(LAST_EXEC_TIME, this , new Long(System
504:                            .currentTimeMillis()));
505:                }
506:
507:                /** Override importClass to allow reloading of classes */
508:                public static void importClass(Context ctx, Scriptable this Obj,
509:                        Object[] args, Function funObj) {
510:                    for (int i = 0; i < args.length; i++) {
511:                        Object clazz = args[i];
512:                        if (!(clazz instanceof  NativeJavaClass)) {
513:                            throw Context
514:                                    .reportRuntimeError("Not a Java class: "
515:                                            + Context.toString(clazz));
516:                        }
517:                        String s = ((NativeJavaClass) clazz).getClassObject()
518:                                .getName();
519:                        String n = s.substring(s.lastIndexOf('.') + 1);
520:                        this Obj.put(n, this Obj, clazz);
521:                    }
522:                }
523:
524:                public void setupPackages(ClassLoader cl) throws Exception {
525:                    final String JAVA_PACKAGE = "JavaPackage";
526:                    if (classLoader != cl) {
527:                        classLoader = cl;
528:                        Scriptable newPackages = new NativeJavaPackage("", cl);
529:                        newPackages.setParentScope(this );
530:                        newPackages.setPrototype(ScriptableObject
531:                                .getClassPrototype(this , JAVA_PACKAGE));
532:                        super .put("Packages", this , newPackages);
533:                        for (int i = 0; i < BUILTIN_PACKAGES.length; i++) {
534:                            String pkgName = BUILTIN_PACKAGES[i];
535:                            Scriptable pkg = new NativeJavaPackage(pkgName, cl);
536:                            pkg.setParentScope(this );
537:                            pkg.setPrototype(ScriptableObject
538:                                    .getClassPrototype(this , JAVA_PACKAGE));
539:                            super .put(pkgName, this , pkg);
540:                        }
541:                    }
542:                }
543:
544:                public ClassLoader getClassLoader() {
545:                    return classLoader;
546:                }
547:            }
548:
549:            private ThreadScope createThreadScope() throws Exception {
550:                return new ThreadScope(scope);
551:            }
552:
553:            /**
554:             * Returns a new Scriptable object to be used as the global scope
555:             * when running the JavaScript scripts in the context of a request.
556:             *
557:             * <p>If you want to maintain the state of global variables across
558:             * multiple invocations of <code>&lt;map:call
559:             * function="..."&gt;</code>, you need to instanciate the session
560:             * object which is a property of the cocoon object
561:             * <code>var session = cocoon.session</code>. This will place the
562:             * newly create Scriptable object in the user's session, where it
563:             * will be retrieved from at the next invocation of {@link #callFunction}.</p>
564:             *
565:             * @exception Exception if an error occurs
566:             */
567:            private void setupContext(Redirector redirector, Context context,
568:                    ThreadScope thrScope) throws Exception {
569:                // Try to retrieve the scope object from the session instance. If
570:                // no scope is found, we create a new one, but don't place it in
571:                // the session.
572:                //
573:                // When a user script "creates" a session using
574:                // cocoon.createSession() in JavaScript, the thrScope is placed in
575:                // the session object, where it's later retrieved from here. This
576:                // behaviour allows multiple JavaScript functions to share the
577:                // same global scope.
578:
579:                FOM_Cocoon cocoon = (FOM_Cocoon) thrScope.get("cocoon",
580:                        thrScope);
581:                long lastExecTime = ((Long) thrScope.get(LAST_EXEC_TIME,
582:                        thrScope)).longValue();
583:                boolean needsRefresh = false;
584:                if (reloadScripts) {
585:                    long now = System.currentTimeMillis();
586:                    if (now >= lastTimeCheck + checkTime) {
587:                        needsRefresh = true;
588:                    }
589:                    lastTimeCheck = now;
590:                }
591:
592:                // We need to setup the FOM_Cocoon object according to the current
593:                // request. Everything else remains the same.
594:                ClassLoader classLoader = getClassLoader(needsRefresh);
595:                Thread.currentThread().setContextClassLoader(classLoader);
596:                thrScope.setupPackages(classLoader);
597:                cocoon.pushCallContext(this , redirector, manager,
598:                        avalonContext, getLogger(), null);
599:
600:                // Check if we need to compile and/or execute scripts
601:                synchronized (compiledScripts) {
602:                    List execList = new ArrayList();
603:                    // If we've never executed scripts in this scope or
604:                    // if reload-scripts is true and the check interval has expired
605:                    // or if new scripts have been specified in the sitemap,
606:                    // then create a list of scripts to compile/execute
607:                    if (lastExecTime == 0 || needsRefresh
608:                            || needResolve.size() > 0) {
609:                        topLevelScripts.addAll(needResolve);
610:                        if (lastExecTime != 0 && !needsRefresh) {
611:                            execList.addAll(needResolve);
612:                        } else {
613:                            execList.addAll(topLevelScripts);
614:                        }
615:                        needResolve.clear();
616:                    }
617:                    // Compile all the scripts first. That way you can set breakpoints
618:                    // in the debugger before they execute.
619:                    for (int i = 0, size = execList.size(); i < size; i++) {
620:                        String sourceURI = (String) execList.get(i);
621:                        ScriptSourceEntry entry = (ScriptSourceEntry) compiledScripts
622:                                .get(sourceURI);
623:                        if (entry == null) {
624:                            Source src = this .sourceresolver
625:                                    .resolveURI(sourceURI);
626:                            entry = new ScriptSourceEntry(src);
627:                            compiledScripts.put(sourceURI, entry);
628:                        }
629:                        // Compile the script if necessary
630:                        entry
631:                                .getScript(context, this .scope, needsRefresh,
632:                                        this );
633:                    }
634:                    // Execute the scripts if necessary
635:                    for (int i = 0, size = execList.size(); i < size; i++) {
636:                        String sourceURI = (String) execList.get(i);
637:                        ScriptSourceEntry entry = (ScriptSourceEntry) compiledScripts
638:                                .get(sourceURI);
639:                        long lastMod = 0;
640:                        if (reloadScripts && lastExecTime != 0) {
641:                            lastMod = entry.getSource().getLastModified();
642:                        }
643:                        Script script = entry.getScript(context, this .scope,
644:                                false, this );
645:                        if (lastExecTime == 0 || lastMod > lastExecTime) {
646:                            script.exec(context, thrScope);
647:                            thrScope.onExec();
648:                        }
649:                    }
650:                }
651:            }
652:
653:            /**
654:             * Compile filename as JavaScript code
655:             *
656:             * @param cx Rhino context
657:             * @param fileName resource uri
658:             * @return compiled script
659:             */
660:            Script compileScript(Context cx, String fileName) throws Exception {
661:                Source src = this .sourceresolver.resolveURI(fileName);
662:                if (src != null) {
663:                    synchronized (compiledScripts) {
664:                        ScriptSourceEntry entry = (ScriptSourceEntry) compiledScripts
665:                                .get(src.getURI());
666:                        Script compiledScript = null;
667:                        if (entry == null) {
668:                            compiledScripts.put(src.getURI(),
669:                                    entry = new ScriptSourceEntry(src));
670:                        } else {
671:                            this .sourceresolver.release(src);
672:                        }
673:                        boolean needsRefresh = reloadScripts
674:                                && (entry.getCompileTime() + checkTime < System
675:                                        .currentTimeMillis());
676:                        compiledScript = entry.getScript(cx, this .scope,
677:                                needsRefresh, this );
678:                        return compiledScript;
679:                    }
680:                }
681:                throw new ResourceNotFoundException(fileName + ": not found");
682:            }
683:
684:            protected Script compileScript(Context cx, Scriptable scope,
685:                    Source src) throws Exception {
686:                PushbackInputStream is = new PushbackInputStream(src
687:                        .getInputStream(), ENCODING_BUF_SIZE);
688:                try {
689:                    String encoding = findEncoding(is);
690:                    Reader reader = encoding == null ? new InputStreamReader(is)
691:                            : new InputStreamReader(is, encoding);
692:                    reader = new BufferedReader(reader);
693:                    Script compiledScript = cx.compileReader(scope, reader, src
694:                            .getURI(), 1, null);
695:                    return compiledScript;
696:                } finally {
697:                    is.close();
698:                }
699:            }
700:
701:            // A charset name can be up to 40 characters taken from the printable characters of US-ASCII
702:            // (see http://www.iana.org/assignments/character-sets). So reading 100 bytes should be more than enough.
703:            private final static int ENCODING_BUF_SIZE = 100;
704:            // Match 'encoding = xxxx' on the first line
705:            REProgram encodingRE = new RECompiler()
706:                    .compile("^.*encoding\\s*=\\s*([^\\s]*)");
707:
708:            /**
709:             * Find the encoding of the stream, or null if not specified
710:             */
711:            String findEncoding(PushbackInputStream is) throws IOException {
712:                // Read some bytes
713:                byte[] buffer = new byte[ENCODING_BUF_SIZE];
714:                int len = is.read(buffer, 0, buffer.length);
715:                // and push them back
716:                is.unread(buffer, 0, len);
717:
718:                // Interpret them as an ASCII string
719:                String str = new String(buffer, 0, len, "ASCII");
720:                RE re = new RE(encodingRE);
721:                if (re.match(str)) {
722:                    return re.getParen(1);
723:                }
724:                return null;
725:            }
726:
727:            /**
728:             * Calls a JavaScript function, passing <code>params</code> as its
729:             * arguments. In addition to this, it makes available the parameters
730:             * through the <code>cocoon.parameters</code> JavaScript array
731:             * (indexed by the parameter names).
732:             *
733:             * @param funName a <code>String</code> value
734:             * @param params a <code>List</code> value
735:             * @param redirector
736:             * @exception Exception if an error occurs
737:             */
738:            public void callFunction(String funName, List params,
739:                    Redirector redirector) throws Exception {
740:                Context context = Context.enter();
741:                context.setOptimizationLevel(OPTIMIZATION_LEVEL);
742:                context.setGeneratingDebug(true);
743:                context.setCompileFunctionsWithDynamicScope(true);
744:                context.setErrorReporter(errorReporter);
745:
746:                LocationTrackingDebugger locationTracker = new LocationTrackingDebugger();
747:                if (!enableDebugger) {
748:                    //FIXME: add a "tee" debugger that allows both to be used simultaneously
749:                    context.setDebugger(locationTracker, null);
750:                }
751:
752:                ThreadScope thrScope = getSessionScope();
753:                synchronized (thrScope) {
754:                    ClassLoader savedClassLoader = Thread.currentThread()
755:                            .getContextClassLoader();
756:                    FOM_Cocoon cocoon = null;
757:                    try {
758:                        try {
759:                            setupContext(redirector, context, thrScope);
760:                            cocoon = (FOM_Cocoon) thrScope.get("cocoon",
761:                                    thrScope);
762:
763:                            // Register the current scope for scripts indirectly called from this function
764:                            FOM_JavaScriptFlowHelper.setFOM_FlowScope(cocoon
765:                                    .getObjectModel(), thrScope);
766:
767:                            if (enableDebugger) {
768:                                if (!getDebugger().isVisible()) {
769:                                    // only raise the debugger window if it isn't already visible
770:                                    getDebugger().setVisible(true);
771:                                }
772:                            }
773:
774:                            int size = (params != null ? params.size() : 0);
775:                            Object[] funArgs = new Object[size];
776:                            Scriptable parameters = context.newObject(thrScope);
777:                            for (int i = 0; i < size; i++) {
778:                                Interpreter.Argument arg = (Interpreter.Argument) params
779:                                        .get(i);
780:                                funArgs[i] = arg.value;
781:                                if (arg.name == null) {
782:                                    arg.name = "";
783:                                }
784:                                parameters.put(arg.name, parameters, arg.value);
785:                            }
786:                            cocoon.setParameters(parameters);
787:
788:                            Object fun;
789:                            try {
790:                                fun = context.compileReader(thrScope,
791:                                        new StringReader(funName), null, 1,
792:                                        null).exec(context, thrScope);
793:                            } catch (EcmaError ee) {
794:                                throw new ResourceNotFoundException(
795:                                        "Function \"javascript:" + funName
796:                                                + "()\" not found");
797:                            }
798:
799:                            // Check count of arguments
800:                            if (fun instanceof  BaseFunction) {
801:                                if (((BaseFunction) fun).getArity() != 0) {
802:                                    getLogger()
803:                                            .error(
804:                                                    "Function '"
805:                                                            + funName
806:                                                            + "' must have no declared arguments! "
807:                                                            + "Use cocoon.parameters to reach parameters passed from the sitemap into the function.");
808:                                }
809:                            }
810:
811:                            thrScope.setLock(true);
812:                            ScriptRuntime.call(context, fun, thrScope, funArgs,
813:                                    thrScope);
814:                        } catch (JavaScriptException ex) {
815:                            throw locationTracker.getException(
816:                                    "Error calling flowscript function "
817:                                            + funName, ex);
818:                        } catch (EcmaError ee) {
819:                            throw locationTracker.getException(
820:                                    "Error calling flowscript function "
821:                                            + funName, ee);
822:                        }
823:                    } finally {
824:                        thrScope.setLock(false);
825:                        setSessionScope(thrScope);
826:                        if (cocoon != null) {
827:                            cocoon.popCallContext();
828:                        }
829:                        Context.exit();
830:                        Thread.currentThread().setContextClassLoader(
831:                                savedClassLoader);
832:                    }
833:                }
834:            }
835:
836:            public void handleContinuation(String id, List params,
837:                    Redirector redirector) throws Exception {
838:                WebContinuation wk = continuationsMgr.lookupWebContinuation(id,
839:                        getInterpreterID());
840:
841:                if (wk == null) {
842:                    /*
843:                     * Throw an InvalidContinuationException to be handled inside the
844:                     * <map:handle-errors> sitemap element.
845:                     */
846:                    throw new InvalidContinuationException(
847:                            "The continuation ID " + id + " is invalid.");
848:                }
849:
850:                Context context = Context.enter();
851:                context.setOptimizationLevel(OPTIMIZATION_LEVEL);
852:                context.setGeneratingDebug(true);
853:                context.setCompileFunctionsWithDynamicScope(true);
854:                LocationTrackingDebugger locationTracker = new LocationTrackingDebugger();
855:                if (!enableDebugger) {
856:                    //FIXME: add a "tee" debugger that allows both to be used simultaneously
857:                    context.setDebugger(locationTracker, null);
858:                }
859:
860:                // Obtain the continuation object from it, and setup the
861:                // FOM_Cocoon object associated in the dynamic scope of the saved
862:                // continuation with the environment and context objects.
863:                Continuation k = (Continuation) wk.getContinuation();
864:                ThreadScope kScope = (ThreadScope) k.getParentScope();
865:                synchronized (kScope) {
866:                    ClassLoader savedClassLoader = Thread.currentThread()
867:                            .getContextClassLoader();
868:                    FOM_Cocoon cocoon = null;
869:                    try {
870:                        Thread.currentThread().setContextClassLoader(
871:                                kScope.getClassLoader());
872:                        cocoon = (FOM_Cocoon) kScope.get("cocoon", kScope);
873:                        kScope.setLock(true);
874:                        cocoon.pushCallContext(this , redirector, manager,
875:                                avalonContext, getLogger(), wk);
876:
877:                        // Register the current scope for scripts indirectly called from this function
878:                        FOM_JavaScriptFlowHelper.setFOM_FlowScope(cocoon
879:                                .getObjectModel(), kScope);
880:
881:                        if (enableDebugger) {
882:                            getDebugger().setVisible(true);
883:                        }
884:                        Scriptable parameters = context.newObject(kScope);
885:                        int size = params != null ? params.size() : 0;
886:                        for (int i = 0; i < size; i++) {
887:                            Interpreter.Argument arg = (Interpreter.Argument) params
888:                                    .get(i);
889:                            parameters.put(arg.name, parameters, arg.value);
890:                        }
891:                        cocoon.setParameters(parameters);
892:                        FOM_WebContinuation fom_wk = new FOM_WebContinuation(wk);
893:                        fom_wk.setParentScope(kScope);
894:                        fom_wk.setPrototype(ScriptableObject.getClassPrototype(
895:                                kScope, fom_wk.getClassName()));
896:                        Object[] args = new Object[] { k, fom_wk };
897:                        try {
898:                            ScriptableObject.callMethod(cocoon,
899:                                    "handleContinuation", args);
900:                        } catch (JavaScriptException ex) {
901:                            throw locationTracker.getException(
902:                                    "Error calling continuation", ex);
903:                        } catch (EcmaError ee) {
904:                            throw locationTracker.getException(
905:                                    "Error calling continuation", ee);
906:                        }
907:                    } finally {
908:                        kScope.setLock(false);
909:                        setSessionScope(kScope);
910:                        if (cocoon != null) {
911:                            cocoon.popCallContext();
912:                        }
913:                        Context.exit();
914:                        Thread.currentThread().setContextClassLoader(
915:                                savedClassLoader);
916:                    }
917:                }
918:            }
919:
920:            public void forwardTo(Scriptable scope, FOM_Cocoon cocoon,
921:                    String uri, Object bizData, FOM_WebContinuation fom_wk,
922:                    Redirector redirector) throws Exception {
923:                setupView(scope, cocoon, fom_wk);
924:                super .forwardTo(uri, bizData, fom_wk == null ? null : fom_wk
925:                        .getWebContinuation(), redirector);
926:            }
927:
928:            // package access as this is called by FOM_Cocoon
929:            void process(Scriptable scope, FOM_Cocoon cocoon, String uri,
930:                    Object bizData, OutputStream out) throws Exception {
931:                setupView(scope, cocoon, null);
932:                super .process(uri, bizData, out);
933:            }
934:
935:            private void setupView(Scriptable scope, FOM_Cocoon cocoon,
936:                    FOM_WebContinuation kont) {
937:                Map objectModel = ContextHelper
938:                        .getObjectModel(this .avalonContext);
939:
940:                // Make the JS live-connect objects available to the view layer
941:                FOM_JavaScriptFlowHelper.setPackages(objectModel,
942:                        (Scriptable) ScriptableObject.getProperty(scope,
943:                                "Packages"));
944:                FOM_JavaScriptFlowHelper.setJavaPackage(objectModel,
945:                        (Scriptable) ScriptableObject
946:                                .getProperty(scope, "java"));
947:
948:                // Make the FOM objects available to the view layer
949:                FOM_JavaScriptFlowHelper.setFOM_Request(objectModel, cocoon
950:                        .jsGet_request());
951:                FOM_JavaScriptFlowHelper.setFOM_Response(objectModel, cocoon
952:                        .jsGet_response());
953:                Request request = ObjectModelHelper.getRequest(objectModel);
954:                Scriptable session = null;
955:                if (request.getSession(false) != null) {
956:                    session = cocoon.jsGet_session();
957:                }
958:                FOM_JavaScriptFlowHelper.setFOM_Session(objectModel, session);
959:
960:                FOM_JavaScriptFlowHelper.setFOM_Context(objectModel, cocoon
961:                        .jsGet_context());
962:                if (kont != null) {
963:                    FOM_JavaScriptFlowHelper.setFOM_WebContinuation(
964:                            objectModel, kont);
965:                }
966:            }
967:        }
www___._j__a_va2___s___.___co___m___ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.