Source Code Cross Referenced for JavaScriptEngine.java in  » Testing » htmlunit » com » gargoylesoftware » htmlunit » javascript » 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 » Testing » htmlunit » com.gargoylesoftware.htmlunit.javascript 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright (c) 2002-2008 Gargoyle Software Inc. All rights reserved.
003:         *
004:         * Redistribution and use in source and binary forms, with or without
005:         * modification, are permitted provided that the following conditions are met:
006:         *
007:         * 1. Redistributions of source code must retain the above copyright notice,
008:         *    this list of conditions and the following disclaimer.
009:         * 2. Redistributions in binary form must reproduce the above copyright notice,
010:         *    this list of conditions and the following disclaimer in the documentation
011:         *    and/or other materials provided with the distribution.
012:         * 3. The end-user documentation included with the redistribution, if any, must
013:         *    include the following acknowledgment:
014:         *
015:         *       "This product includes software developed by Gargoyle Software Inc.
016:         *        (http://www.GargoyleSoftware.com/)."
017:         *
018:         *    Alternately, this acknowledgment may appear in the software itself, if
019:         *    and wherever such third-party acknowledgments normally appear.
020:         * 4. The name "Gargoyle Software" must not be used to endorse or promote
021:         *    products derived from this software without prior written permission.
022:         *    For written permission, please contact info@GargoyleSoftware.com.
023:         * 5. Products derived from this software may not be called "HtmlUnit", nor may
024:         *    "HtmlUnit" appear in their name, without prior written permission of
025:         *    Gargoyle Software Inc.
026:         *
027:         * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
028:         * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
029:         * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
030:         * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
031:         * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
032:         * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
033:         * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
034:         * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
035:         * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
036:         * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
037:         */
038:        package com.gargoylesoftware.htmlunit.javascript;
039:
040:        import java.io.Serializable;
041:        import java.lang.reflect.InvocationTargetException;
042:        import java.lang.reflect.Member;
043:        import java.lang.reflect.Method;
044:        import java.util.Collections;
045:        import java.util.HashMap;
046:        import java.util.Iterator;
047:        import java.util.Map;
048:        import java.util.WeakHashMap;
049:
050:        import org.apache.commons.lang.StringUtils;
051:        import org.apache.commons.logging.Log;
052:        import org.apache.commons.logging.LogFactory;
053:        import org.mozilla.javascript.Context;
054:        import org.mozilla.javascript.ContextAction;
055:        import org.mozilla.javascript.ContextFactory;
056:        import org.mozilla.javascript.Function;
057:        import org.mozilla.javascript.FunctionObject;
058:        import org.mozilla.javascript.Script;
059:        import org.mozilla.javascript.Scriptable;
060:        import org.mozilla.javascript.ScriptableObject;
061:
062:        import com.gargoylesoftware.htmlunit.Assert;
063:        import com.gargoylesoftware.htmlunit.BrowserVersion;
064:        import com.gargoylesoftware.htmlunit.ScriptException;
065:        import com.gargoylesoftware.htmlunit.ScriptPreProcessor;
066:        import com.gargoylesoftware.htmlunit.WebClient;
067:        import com.gargoylesoftware.htmlunit.WebResponse;
068:        import com.gargoylesoftware.htmlunit.WebWindow;
069:        import com.gargoylesoftware.htmlunit.html.DomNode;
070:        import com.gargoylesoftware.htmlunit.html.HtmlElement;
071:        import com.gargoylesoftware.htmlunit.html.HtmlPage;
072:        import com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration;
073:        import com.gargoylesoftware.htmlunit.javascript.configuration.JavaScriptConfiguration;
074:        import com.gargoylesoftware.htmlunit.javascript.host.Element;
075:        import com.gargoylesoftware.htmlunit.javascript.host.Window;
076:
077:        /**
078:         * A wrapper for the <a href="http://www.mozilla.org/rhino">Rhino javascript engine</a>
079:         * that provides browser specific features.<br/>
080:         * Like all classes in this package, this class is not intended for direct use
081:         * and may change without notice.
082:         *
083:         * @version $Revision: 2158 $
084:         * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
085:         * @author <a href="mailto:chen_jun@users.sourceforge.net">Chen Jun</a>
086:         * @author David K. Taylor
087:         * @author Chris Erskine
088:         * @author <a href="mailto:bcurren@esomnie.com">Ben Curren</a>
089:         * @author David D. Kilzer
090:         * @author Marc Guillemot
091:         * @author Daniel Gredler
092:         * @author Ahmed Ashour
093:         * @see <a href="http://groups-beta.google.com/group/netscape.public.mozilla.jseng/browse_thread/thread/b4edac57329cf49f/069e9307ec89111f">
094:         * Rhino and Java Browser</a>
095:         */
096:        public class JavaScriptEngine implements  Serializable {
097:
098:            private static final long serialVersionUID = -5414040051465432088L;
099:            private final WebClient webClient_;
100:            private static final Log ScriptEngineLog_ = LogFactory
101:                    .getLog(JavaScriptEngine.class);
102:
103:            private static final ThreadLocal javaScriptRunning_ = new ThreadLocal();
104:            /**
105:             * Cache parsed scripts (only for js files, not for js code embedded in html code)
106:             * The WeakHashMap allows cached scripts to be GCed when the WebResponses are not retained
107:             * in the {@link com.gargoylesoftware.htmlunit.Cache} anymore.
108:             */
109:            private final transient Map cachedScripts_ = Collections
110:                    .synchronizedMap(new WeakHashMap());
111:
112:            /**
113:             * Key used to place the scope in which the execution of some javascript code
114:             * started as thread local attribute in current context.<br/>
115:             * This is needed to resolve some relative locations relatively to the page
116:             * in which the script is executed and not to the page which location is changed.
117:             */
118:            public static final String KEY_STARTING_SCOPE = "startingScope";
119:
120:            /**
121:             * Initialize a context listener so we can count JS contexts and make sure we
122:             * are freeing them as necessary.
123:             */
124:            static {
125:                final HtmlUnitContextFactory contextFactory = new HtmlUnitContextFactory(
126:                        getScriptEngineLog());
127:                ContextFactory.initGlobal(contextFactory);
128:            }
129:
130:            /**
131:             * Create an instance for the specified webclient
132:             *
133:             * @param webClient The webClient that will own this engine.
134:             */
135:            public JavaScriptEngine(final WebClient webClient) {
136:                webClient_ = webClient;
137:            }
138:
139:            /**
140:             * Return the web client that this engine is associated with.
141:             * @return The web client.
142:             */
143:            public final WebClient getWebClient() {
144:                return webClient_;
145:            }
146:
147:            /**
148:             * Perform initialization for the given webWindow
149:             * @param webWindow the web window to initialize for
150:             */
151:            public void initialize(final WebWindow webWindow) {
152:                Assert.notNull("webWindow", webWindow);
153:
154:                final ContextAction action = new ContextAction() {
155:                    public Object run(final Context cx) {
156:                        try {
157:                            init(webWindow, cx);
158:                        } catch (final Exception e) {
159:                            getLog()
160:                                    .error(
161:                                            "Exception while initializing JavaScript for the page",
162:                                            e);
163:                            throw new ScriptException(null, e); // BUG: null is not useful.
164:                        }
165:
166:                        return null;
167:                    }
168:                };
169:
170:                Context.call(action);
171:            }
172:
173:            /**
174:             * Initializes all the JS stuff for the window
175:             * @param webWindow the web window
176:             * @param context the current context
177:             * @throws Exception if something goes wrong
178:             */
179:            private void init(final WebWindow webWindow, final Context context)
180:                    throws Exception {
181:                final WebClient webClient = webWindow.getWebClient();
182:                final Map prototypes = new HashMap();
183:                final Map prototypesPerJSName = new HashMap();
184:                final Window window = new Window(this );
185:                final JavaScriptConfiguration jsConfig = JavaScriptConfiguration
186:                        .getInstance(webClient.getBrowserVersion());
187:                context.initStandardObjects(window);
188:                StringPrimitivePrototypeBugFixer.installWorkaround(window);
189:
190:                // put custom object to be called as very last prototype to call the fallback getter (if any)
191:                final Scriptable fallbackCaller = new ScriptableObject() {
192:                    private static final long serialVersionUID = -7124423159070941606L;
193:
194:                    public Object get(final String name, final Scriptable start) {
195:                        if (start instanceof  ScriptableWithFallbackGetter) {
196:                            return ((ScriptableWithFallbackGetter) start)
197:                                    .getWithFallback(name);
198:                        }
199:                        return NOT_FOUND;
200:                    }
201:
202:                    public String getClassName() {
203:                        return "htmlUnitHelper-fallbackCaller";
204:                    }
205:                };
206:                ScriptableObject.getObjectPrototype(window).setPrototype(
207:                        fallbackCaller);
208:
209:                final Iterator it = jsConfig.keySet().iterator();
210:                while (it.hasNext()) {
211:                    final String jsClassName = (String) it.next();
212:                    final ClassConfiguration config = jsConfig
213:                            .getClassConfiguration(jsClassName);
214:                    final boolean isWindow = Window.class.getName().equals(
215:                            config.getLinkedClass().getName());
216:                    if (isWindow) {
217:                        configureConstantsPropertiesAndFunctions(config, window);
218:                    } else {
219:                        final Scriptable prototype = configureClass(config,
220:                                window);
221:                        if (config.isJsObject()) {
222:                            prototypes.put(config.getLinkedClass(), prototype);
223:
224:                            // for FF, place object with prototype property in Window scope
225:                            if (!getWebClient().getBrowserVersion().isIE()) {
226:                                final Scriptable obj = (Scriptable) config
227:                                        .getLinkedClass().newInstance();
228:                                obj.put("prototype", obj, prototype);
229:                                obj.setPrototype(prototype);
230:                                obj.setParentScope(window);
231:                                ScriptableObject.defineProperty(window, config
232:                                        .getClassName(), obj,
233:                                        ScriptableObject.DONTENUM);
234:                                if (obj.getClass() == Element.class) {
235:                                    final DomNode domNode = new HtmlElement(
236:                                            null, "", (HtmlPage) webWindow
237:                                                    .getEnclosedPage(), null) {
238:                                        private static final long serialVersionUID = -5614158965497997095L;
239:                                    };
240:                                    ((SimpleScriptable) obj)
241:                                            .setDomNode(domNode);
242:                                }
243:                            }
244:                        }
245:                        prototypesPerJSName.put(config.getClassName(),
246:                                prototype);
247:                    }
248:                }
249:
250:                // once all prototypes have been build, it's possible to configure the chains
251:                final Scriptable objectPrototype = ScriptableObject
252:                        .getObjectPrototype(window);
253:                for (final Iterator iter = prototypesPerJSName.entrySet()
254:                        .iterator(); iter.hasNext();) {
255:                    final Map.Entry entry = (Map.Entry) iter.next();
256:                    final String name = (String) entry.getKey();
257:                    final ClassConfiguration config = jsConfig
258:                            .getClassConfiguration(name);
259:                    final Scriptable prototype = (Scriptable) entry.getValue();
260:                    if (!StringUtils.isEmpty(config.getExtendedClass())) {
261:                        final Scriptable parentPrototype = (Scriptable) prototypesPerJSName
262:                                .get(config.getExtendedClass());
263:                        prototype.setPrototype(parentPrototype);
264:                    } else {
265:                        prototype.setPrototype(objectPrototype);
266:                    }
267:                }
268:
269:                // eval hack (cf unit tests testEvalScopeOtherWindow and testEvalScopeLocal
270:                final Class[] evalFnTypes = { String.class };
271:                final Member evalFn = Window.class.getMethod("custom_eval",
272:                        evalFnTypes);
273:                final FunctionObject jsCustomEval = new FunctionObject("eval",
274:                        evalFn, window);
275:                window.associateValue("custom_eval", jsCustomEval);
276:
277:                for (final Iterator classnames = jsConfig.keySet().iterator(); classnames
278:                        .hasNext();) {
279:                    final String jsClassName = (String) classnames.next();
280:                    final ClassConfiguration config = jsConfig
281:                            .getClassConfiguration(jsClassName);
282:                    final Method jsConstructor = config.getJsConstructor();
283:                    if (jsConstructor != null) {
284:                        final Scriptable prototype = (Scriptable) prototypesPerJSName
285:                                .get(jsClassName);
286:                        if (prototype != null) {
287:                            final FunctionObject jsCtor = new FunctionObject(
288:                                    jsClassName, jsConstructor, window);
289:                            jsCtor.addAsConstructor(window, prototype);
290:                        }
291:                    }
292:                }
293:
294:                window.setPrototypes(prototypes);
295:                window.initialize(webWindow);
296:            }
297:
298:            /**
299:             * Configures the specified class for access via JavaScript.
300:             * @param config The configuration settings for the class to be configured.
301:             * @param window The scope within which to configure the class.
302:             * @throws InstantiationException If the new class cannot be instantiated
303:             * @throws IllegalAccessException If we don't have access to create the new instance.
304:             * @throws InvocationTargetException if an exception is thrown during creation of the new object.
305:             * @return the created prototype
306:             */
307:            private Scriptable configureClass(final ClassConfiguration config,
308:                    final Scriptable window) throws InstantiationException,
309:                    IllegalAccessException, InvocationTargetException {
310:
311:                final Class jsHostClass = config.getLinkedClass();
312:                final ScriptableObject prototype = (ScriptableObject) jsHostClass
313:                        .newInstance();
314:                prototype.setParentScope(window);
315:
316:                configureConstantsPropertiesAndFunctions(config, prototype);
317:
318:                return prototype;
319:            }
320:
321:            /**
322:             * Configure constants, properties and functions on the object
323:             * @param config the configuration for the object
324:             * @param scriptable the object to configure
325:             */
326:            private void configureConstantsPropertiesAndFunctions(
327:                    final ClassConfiguration config,
328:                    final ScriptableObject scriptable) {
329:
330:                // the constants
331:                for (final Iterator constantsIterator = config.constants()
332:                        .iterator(); constantsIterator.hasNext();) {
333:                    final String constant = (String) constantsIterator.next();
334:                    final Class linkedClass = config.getLinkedClass();
335:                    try {
336:                        final Object value = linkedClass.getField(constant)
337:                                .get(null);
338:                        scriptable.defineProperty(constant, value,
339:                                ScriptableObject.CONST);
340:                    } catch (final Exception e) {
341:                        throw Context.reportRuntimeError("Can not get field '"
342:                                + constant + "' for type: "
343:                                + config.getClassName());
344:                    }
345:                }
346:                // the properties
347:                for (final Iterator propertiesIterator = config.propertyKeys()
348:                        .iterator(); propertiesIterator.hasNext();) {
349:                    final String entryKey = (String) propertiesIterator.next();
350:                    final Method readMethod = config
351:                            .getPropertyReadMethod(entryKey);
352:                    final Method writeMethod = config
353:                            .getPropertyWriteMethod(entryKey);
354:                    scriptable.defineProperty(entryKey, null, readMethod,
355:                            writeMethod, ScriptableObject.EMPTY);
356:                }
357:
358:                // the functions
359:                for (final Iterator functionsIterator = config.functionKeys()
360:                        .iterator(); functionsIterator.hasNext();) {
361:                    final String entryKey = (String) functionsIterator.next();
362:                    final Method method = config.getFunctionMethod(entryKey);
363:                    final FunctionObject functionObject = new FunctionObject(
364:                            entryKey, method, scriptable);
365:                    scriptable.defineProperty(entryKey, functionObject,
366:                            ScriptableObject.EMPTY);
367:                }
368:            }
369:
370:            /**
371:             * Return the log object for this class
372:             * @return The log object
373:             */
374:            protected Log getLog() {
375:                return LogFactory.getLog(getClass());
376:            }
377:
378:            /**
379:             * Compiles the specified javascript code in the context of a given html page.
380:             *
381:             * @param htmlPage The page that the code will execute within
382:             * @param sourceCode The javascript code to execute.
383:             * @param sourceName The name that will be displayed on error conditions.
384:             * @param startLine the line at which the script source starts
385:             * @return The result of executing the specified code.
386:             */
387:            public Script compile(final HtmlPage htmlPage, String sourceCode,
388:                    final String sourceName, final int startLine) {
389:
390:                Assert.notNull("sourceCode", sourceCode);
391:
392:                // Pre process the source code
393:                sourceCode = preProcess(htmlPage, sourceCode, sourceName, null);
394:
395:                // PreProcess IE Conditional Compilation if needed
396:                final BrowserVersion browserVersion = htmlPage.getWebClient()
397:                        .getBrowserVersion();
398:                if (browserVersion.isIE()
399:                        && browserVersion.getBrowserVersionNumeric() >= 4) {
400:                    final ScriptPreProcessor ieCCPreProcessor = new IEConditionalCompilationScriptPreProcessor();
401:                    sourceCode = ieCCPreProcessor.preProcess(htmlPage,
402:                            sourceCode, sourceName, null);
403:                }
404:
405:                // Remove HTML comments around the source if needed
406:                final String sourceCodeTrimmed = sourceCode.trim();
407:                if (sourceCodeTrimmed.startsWith("<!--")) {
408:                    sourceCode = sourceCode.replaceFirst("<!--", "// <!--");
409:                }
410:                // IE ignores the last line containing uncommented -->
411:                if (getWebClient().getBrowserVersion().isIE()
412:                        && sourceCodeTrimmed.endsWith("-->")) {
413:                    final int lastDoubleSlash = sourceCode.lastIndexOf("//");
414:                    final int lastNewLine = Math.max(sourceCode
415:                            .lastIndexOf('\n'), sourceCode.lastIndexOf('\r'));
416:                    if (lastNewLine > lastDoubleSlash) {
417:                        sourceCode = sourceCode.substring(0, lastNewLine);
418:                    }
419:                }
420:
421:                final Scriptable scope = getScope(htmlPage, null);
422:                final String source = sourceCode;
423:                final ContextAction action = new HtmlUnitContextAction(scope,
424:                        htmlPage) {
425:                    public Object doRun(final Context cx) {
426:                        return cx.compileString(source, sourceName, startLine,
427:                                null);
428:                    }
429:
430:                    protected String getSourceCode(final Context cx) {
431:                        return source;
432:                    }
433:                };
434:
435:                return (Script) Context.call(action);
436:            }
437:
438:            /**
439:             * Execute the specified javascript code in the context of a given html page.
440:             *
441:             * @param htmlPage The page that the code will execute within
442:             * @param sourceCode The javascript code to execute.
443:             * @param sourceName The name that will be displayed on error conditions.
444:             * @param startLine the line at which the script source starts
445:             * @return The result of executing the specified code.
446:             */
447:            public Object execute(final HtmlPage htmlPage,
448:                    final String sourceCode, final String sourceName,
449:                    final int startLine) {
450:
451:                final Script script = compile(htmlPage, sourceCode, sourceName,
452:                        startLine);
453:                return execute(htmlPage, script);
454:            }
455:
456:            /**
457:             * Execute the specified javascript code in the context of a given html page.
458:             *
459:             * @param htmlPage The page that the code will execute within
460:             * @param script the script to execute
461:             * @return The result of executing the specified code.
462:             */
463:            public Object execute(final HtmlPage htmlPage, final Script script) {
464:
465:                final Scriptable scope = getScope(htmlPage, null);
466:
467:                final ContextAction action = new HtmlUnitContextAction(scope,
468:                        htmlPage) {
469:                    public Object doRun(final Context cx) {
470:                        return script.exec(cx, scope);
471:                    }
472:
473:                    protected String getSourceCode(final Context cx) {
474:                        return null;
475:                    }
476:                };
477:
478:                return Context.call(action);
479:            }
480:
481:            /**
482:             * Call a JavaScript function and return the result.
483:             * @param htmlPage The page
484:             * @param javaScriptFunction The function to call.
485:             * @param thisObject The this object for class method calls.
486:             * @param args The list of arguments to pass to the function.
487:             * @param htmlElement The html element that will act as the context.
488:             * @return The result of the function call.
489:             */
490:            public Object callFunction(final HtmlPage htmlPage,
491:                    final Object javaScriptFunction, final Object this Object,
492:                    final Object[] args, final DomNode htmlElement) {
493:
494:                final Scriptable scope = getScope(htmlPage, htmlElement);
495:
496:                final Function function = (Function) javaScriptFunction;
497:                final ContextAction action = new HtmlUnitContextAction(scope,
498:                        htmlPage) {
499:                    public Object doRun(final Context cx) {
500:                        return callFunction(htmlPage, function, cx, scope,
501:                                (Scriptable) this Object, args);
502:                    }
503:
504:                    protected String getSourceCode(final Context cx) {
505:                        return cx.decompileFunction(function, 2);
506:                    }
507:                };
508:                return Context.call(action);
509:            }
510:
511:            private Scriptable getScope(final HtmlPage htmlPage,
512:                    final DomNode htmlElement) {
513:                final Scriptable scope;
514:                if (htmlElement != null) {
515:                    scope = htmlElement.getScriptObject();
516:                } else {
517:                    scope = (Window) htmlPage.getEnclosingWindow()
518:                            .getScriptObject();
519:                }
520:                return scope;
521:            }
522:
523:            /**
524:             * Calls the given function taking care of synchronization issues.
525:             * @param htmlPage the html page that caused this script to executed
526:             * @param function the js function to execute
527:             * @param context the context in which execution should occur
528:             * @param scope the execution scope
529:             * @param thisObject the 'this' object
530:             * @param args the function's arguments
531:             * @return the function result
532:             */
533:            public Object callFunction(final HtmlPage htmlPage,
534:                    final Function function, final Context context,
535:                    final Scriptable scope, final Scriptable this Object,
536:                    final Object[] args) {
537:
538:                synchronized (htmlPage) // 2 scripts can't be executed in parallel for one page
539:                {
540:                    return function.call(context, scope, this Object, args);
541:                }
542:            }
543:
544:            /**
545:             * Indicates if JavaScript is running in current thread. <br/>
546:             * This allows code to know if there own evaluation is has been  triggered by some JS code.
547:             * @return <code>true</code> if JavaScript is running.
548:             */
549:            public boolean isScriptRunning() {
550:                return Boolean.TRUE.equals(javaScriptRunning_.get());
551:            }
552:
553:            /**
554:             * Set the number of milliseconds a script is allowed to execute before
555:             * being terminated. A value of 0 or less means no timeout.
556:             *
557:             * @param timeout the timeout value
558:             */
559:            public static void setTimeout(final long timeout) {
560:                HtmlUnitContextFactory.setTimeout(timeout);
561:            }
562:
563:            /**
564:             * Returns the number of milliseconds a script is allowed to execute before
565:             * being terminated. A value of 0 or less means no timeout.
566:             *
567:             * @return the timeout value
568:             */
569:            public static long getTimeout() {
570:                return HtmlUnitContextFactory.getTimeout();
571:            }
572:
573:            /**
574:             * Facility for ContextAction usage.
575:             * ContextAction should be preferred because according to Rhino doc it
576:             * "guarantees proper association of Context instances with the current thread and is faster".
577:             */
578:            private abstract class HtmlUnitContextAction implements 
579:                    ContextAction {
580:                private final Scriptable scope_;
581:                private final HtmlPage htmlPage_;
582:
583:                public HtmlUnitContextAction(final Scriptable scope,
584:                        final HtmlPage htmlPage) {
585:                    scope_ = scope;
586:                    htmlPage_ = htmlPage;
587:                }
588:
589:                public final Object run(final Context cx) {
590:                    final Boolean javaScriptAlreadyRunning = (Boolean) javaScriptRunning_
591:                            .get();
592:                    javaScriptRunning_.set(Boolean.TRUE);
593:
594:                    try {
595:                        cx.putThreadLocal(KEY_STARTING_SCOPE, scope_);
596:                        synchronized (htmlPage_) // 2 scripts can't be executed in parallel for one page
597:                        {
598:                            return doRun(cx);
599:                        }
600:                    } catch (final Exception e) {
601:                        final ScriptException scriptException = new ScriptException(
602:                                htmlPage_, e, getSourceCode(cx));
603:                        if (getWebClient().isThrowExceptionOnScriptError()) {
604:                            throw scriptException;
605:                        } else {
606:                            // use a ScriptException to log it because it provides good information
607:                            // on the source code
608:                            getLog().info("Caught script exception",
609:                                    scriptException);
610:                            return null;
611:                        }
612:                    } catch (final TimeoutError e) {
613:                        if (getWebClient().isThrowExceptionOnScriptError()) {
614:                            throw new RuntimeException(e);
615:                        } else {
616:                            getLog().info("Caught script timeout error", e);
617:                            return null;
618:                        }
619:                    } finally {
620:                        javaScriptRunning_.set(javaScriptAlreadyRunning);
621:                    }
622:                }
623:
624:                protected abstract Object doRun(final Context cx);
625:
626:                protected abstract String getSourceCode(final Context cx);
627:            }
628:
629:            /**
630:             * Return the log object that is being used to log information about the script engine.
631:             * @return The log
632:             */
633:            public static Log getScriptEngineLog() {
634:                return ScriptEngineLog_;
635:            }
636:
637:            /**
638:             * Pre process the specified source code in the context of the given page using the processor specified
639:             * in the webclient. This method delegates to the pre processor handler specified in the
640:             * <code>WebClient</code>. If no pre processor handler is defined, the original source code is returned
641:             * unchanged.
642:             * @param htmlPage The page
643:             * @param sourceCode The code to process.
644:             * @param sourceName A name for the chunk of code.  This will be used in error messages.
645:             * @param htmlElement The html element that will act as the context.
646:             * @return The source code after being pre processed
647:             * @see com.gargoylesoftware.htmlunit.ScriptPreProcessor
648:             */
649:            public String preProcess(final HtmlPage htmlPage,
650:                    final String sourceCode, final String sourceName,
651:                    final HtmlElement htmlElement) {
652:
653:                String newSourceCode = sourceCode;
654:                final ScriptPreProcessor preProcessor = getWebClient()
655:                        .getScriptPreProcessor();
656:                if (preProcessor != null) {
657:                    newSourceCode = preProcessor.preProcess(htmlPage,
658:                            sourceCode, sourceName, htmlElement);
659:                    if (newSourceCode == null) {
660:                        newSourceCode = "";
661:                    }
662:                }
663:                return newSourceCode;
664:            }
665:
666:            /**
667:             * Get the cached script for the given response.
668:             * @param webResponse the response corresponding to the script code
669:             * @return the parsed script
670:             */
671:            public Script getCachedScript(final WebResponse webResponse) {
672:                return (Script) cachedScripts_.get(webResponse);
673:            }
674:
675:            /**
676:             * Cache a parsed script
677:             * @param webResponse the response corresponding to the script code. A weak reference to this object
678:             * will be used as key for the cache.
679:             * @param script the parsed script to cache
680:             */
681:            public void cacheScript(final WebResponse webResponse,
682:                    final Script script) {
683:                cachedScripts_.put(webResponse, script);
684:            }
685:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.