Source Code Cross Referenced for OscriptInterpreter.java in  » Scripting » oscript-2.10.4 » oscript » 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 » Scripting » oscript 2.10.4 » oscript 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*=============================================================================
002:         *     Copyright Texas Instruments 2000-2004.  All Rights Reserved.
003:         *   
004:         * This program is free software; you can redistribute it and/or
005:         * modify it under the terms of the GNU Lesser General Public
006:         * License as published by the Free Software Foundation; either
007:         * version 2 of the License, or (at your option) any later version.
008:         * 
009:         * This program is distributed in the hope that it will be useful,
010:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
011:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
012:         * Lesser General Public License for more details.
013:         * 
014:         * You should have received a copy of the GNU Lesser General Public
015:         * License along with this library; if not, write to the Free Software
016:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
017:         * 
018:         * $ProjectHeader: OSCRIPT 0.155 Fri, 20 Dec 2002 18:34:22 -0800 rclark $
019:         */
020:
021:        package oscript;
022:
023:        import oscript.util.StackFrame;
024:        import oscript.fs.*;
025:        import oscript.data.*;
026:        import oscript.exceptions.*;
027:        import oscript.syntaxtree.*;
028:        import oscript.interpreter.*;
029:        import oscript.compiler.*;
030:        import oscript.parser.*;
031:
032:        import java.io.*;
033:        import java.util.*;
034:        import java.net.URL;
035:        import java.net.URLClassLoader;
036:
037:        /**
038:         * The toplevel and main interface for the interpreter.  There can only be
039:         * one instance of this object.  The scope object can be used to create
040:         * logically isolated interpreter "instances".
041:         * <p>
042:         * This does need some cleanup, and perhaps should be a front-end for other
043:         * stuff someone embedding this in an application might want, such as
044:         * creating a new scope...
045:         * <p>
046:         * Description of properties that are interesting:
047:         * <table>
048:         *   <tr>
049:         *     <th>property</th>
050:         *     <th>description</th>
051:         *     <th>regular default</th>
052:         *     <th>webstart default</th>
053:         *   </tr>
054:         *   <tr>
055:         *     <td>oscript.cache.path</td>
056:         *     <td>where the cache directory is created</th>
057:         *     <td>$CWD/.cache</td>
058:         *     <td>$HOME/.cache</td>
059:         *   </tr>
060:         *   <tr>
061:         *     <td>oscript.cwd</td>
062:         *     <td>the current working directory</td>
063:         *     <td>$CWD</td>
064:         *     <td>$HOME/Desktop || $HOME</td>
065:         *   </tr>
066:         * </table>
067:         * 
068:         * @author Rob Clark (rob@ti.com)
069:         */
070:        public class OscriptInterpreter {
071:
072:            private static boolean useCompiler = true;
073:            private static Scope globalScope = null;
074:            private static LinkedList parserList = new LinkedList();
075:            private static LinkedList scriptPathList = new LinkedList();
076:            private static String[] scriptPaths; // cached version of scriptPathList
077:            private static Hashtable nodeEvaluatorCacheTable;
078:            private static ClassLoader classLoader;
079:
080:            private static final boolean TRACE_EVAL = "true".equals(System
081:                    .getProperty("oscript.trace.eval", "false"));
082:
083:            public final static NodeEvaluator EMPTY_EXPR_LIST_EVALUATOR;
084:
085:            /**
086:             * the CACHE_VERSION should change any time a change is made in the interpreter
087:             * that could cause incompatibility with previously serialized cache entries.  It
088:             * is made part of the path to serialized cache entry, so entries serialized with
089:             * different cache versions will not conflict.
090:             */
091:            public static final String CACHE_VERSION = 23 + "_"
092:                    + System.getProperty("java.version").replace('.', '_');
093:
094:            private static final boolean webstart = "true".equals(System
095:                    .getProperty("oscript.webstart"));
096:            private static final String cachePath = System.getProperty(
097:                    "oscript.cache.path", webstart ? System
098:                            .getProperty("user.home")
099:                            + "/.cache" : ".cache");
100:
101:            static {
102:                System.setProperty("oscript.cache.path", (new java.io.File(
103:                        cachePath)).getAbsolutePath());
104:            }
105:
106:            private static ClassLoader cacheClassLoader;
107:
108:            public static Class loadClassFromCache(String className)
109:                    throws ClassNotFoundException {
110:                return CompilerClassLoader.forName(className, true,
111:                        cacheClassLoader);
112:            }
113:
114:            // XXX clean this up!  It should have some way to register factories, etc...
115:            private static NodeEvaluatorFactory nodeCompiler;
116:            private static NodeEvaluatorFactory nodeInterpreter;
117:
118:            public static Value DEFAULT_ARRAY_SORT_COMPARISION_FXN;
119:
120:            static {
121:                try {
122:                    classLoader = CompilerClassLoader.getCompilerClassLoader();
123:                    cacheClassLoader = new URLClassLoader(
124:                            new URL[] { (new File(cachePath + '/')).toURL() },
125:                            classLoader);
126:                    //      registerClassLoader(cacheClassLoader);
127:
128:                    flushNodeEvaluatorCache();
129:                    addScriptPath((new java.io.File(".")).getAbsolutePath());
130:                    addParser(new DefaultParser());
131:
132:                    // mount the root filesystems:
133:                    File[] roots = File.listRoots();
134:                    for (int i = 0; i < roots.length; i++)
135:                        AbstractFileSystem.mount(new LocalFileSystem(roots[i]),
136:                                "/" + roots[i]);
137:
138:                    // mount /cache:
139:                    AbstractFileSystem.mount(new LocalFileSystem(cachePath),
140:                            "/cache");
141:
142:                    String cwd;
143:                    if (webstart) {
144:                        cwd = "/" + System.getProperty("user.home");
145:
146:                        // look for a desktop folder, and use that instead if we find one...
147:                        // this should be good for macosx and windows... but others?
148:                        if ((new File(cwd + "/Desktop")).exists())
149:                            cwd += "/Desktop";
150:                    } else {
151:                        cwd = "/" + (new File(".")).getAbsolutePath();
152:                    }
153:
154:                    // big ugly hack for windoze:
155:                    if (System.getProperty("os.name").toLowerCase().indexOf(
156:                            "windows") != -1)
157:                        if ((cwd.length() > 2) && (cwd.charAt(2) == ':'))
158:                            cwd = "/" + Character.toUpperCase(cwd.charAt(1))
159:                                    + cwd.substring(2);
160:
161:                    // if oscript.cwd property is set, it takes precendence:
162:                    cwd = System.getProperty("oscript.cwd", cwd);
163:                    System.setProperty("oscript.cwd", cwd);
164:
165:                    AbstractFileSystem.setCwd(cwd);
166:
167:                    // also, look in the current user.dir for scripts:
168:                    addScriptPath(AbstractFileSystem.getCwd());
169:
170:                    System.setProperty("user.dir.orig", "/"
171:                            + System.getProperty("user.dir"));
172:                    System.setProperty("user.dir", cwd);
173:
174:                    nodeCompiler = new CompiledNodeEvaluatorFactory();
175:                    nodeInterpreter = new InterpretedNodeEvaluatorFactory();
176:
177:                    // and finally load and evaluate base.os:
178:                    eval(resolve("base.os", false));
179:
180:                    DEFAULT_ARRAY_SORT_COMPARISION_FXN = eval("pkg.system.__defaultArraySortComparision;");
181:
182:                } catch (Throwable e) {
183:                    e.printStackTrace();
184:                }
185:            }
186:
187:            /*=======================================================================*/
188:            /**
189:             * Get a descriptive version string.
190:             */
191:            public static String getVersionString() {
192:                String vname = Version.getVersionName();
193:                int vnum = Version.getVersionNumber();
194:
195:                return "ObjectScript " + vname + " (r" + vnum + ")";
196:            }
197:
198:            /*=======================================================================*/
199:            /**
200:             * Set whether the compiler should be used or not. 
201:             * 
202:             * @param useCompiler  iff <code>true</code>, enabled compiler, otherwise
203:             *    use only the interpreter
204:             */
205:            public static void useCompiler(boolean useCompiler) {
206:                /* NOTE: currently the RegressionTestDriver depends on the behavior of
207:                 *       eval(AbstractFile) always creating a CompiledNodeEvaluator if 
208:                 *       useCompiler is true, and an InterpretedNodeEvaluator if not.
209:                 *       If this ever changes, a different interface will need to be
210:                 *       created to give the RegressionTestDriver better control this
211:                 */
212:                OscriptInterpreter.useCompiler = useCompiler;
213:            }
214:
215:            /*=======================================================================*/
216:            /**
217:             * Flush the node-evaluator-cache...
218:             */
219:            static void flushNodeEvaluatorCache() {
220:                nodeEvaluatorCacheTable = new Hashtable();
221:            }
222:
223:            /*=======================================================================*/
224:            /**
225:             * Set the input stream.
226:             * 
227:             * @param in           the stream to use for input
228:             */
229:            public static void setIn(InputStream in) {
230:                OscriptBuiltins.setIn(in);
231:            }
232:
233:            /*=======================================================================*/
234:            /**
235:             * Set the output stream.
236:             * 
237:             * @param out          the stream to use for output
238:             */
239:            public static void setOut(PrintStream out) {
240:                OscriptBuiltins.setOut(out);
241:            }
242:
243:            /*=======================================================================*/
244:            /**
245:             * Set the error stream.
246:             * 
247:             * @param err          the stream to use for error output
248:             */
249:            public static void setErr(PrintStream err) {
250:                OscriptBuiltins.setErr(err);
251:            }
252:
253:            /*=======================================================================*/
254:            /**
255:             * Get the global scope object.  The <code>globalScope</code> is static,
256:             * meaning that all script code in an application shares a single global
257:             * scope.  But, since the interpreter is multi-threaded, you can achieve
258:             * the same effect of having multiple interpreter instances by creating
259:             * a new level of scope (ie with <code>globalScope</code> as it's parent,
260:             * an evaluate within that scope.
261:             * 
262:             * @return the <code>globalScope</code> object
263:             */
264:            public static Scope getGlobalScope() {
265:                if (globalScope == null) {
266:                    globalScope = new GlobalScope();
267:                    OscriptBuiltins.init();
268:                }
269:
270:                return globalScope;
271:            }
272:
273:            /**
274:             * Register a class loader that we can delegate the act of resolving
275:             * classes.  This allows the user of ObjectScript to give us the
276:             * ability to load classes that we might not otherwise have access
277:             * to.
278:             */
279:            public static void registerClassLoader(ClassLoader loader) {
280:                CompilerClassLoader.registerClassLoader(loader);
281:            }
282:
283:            /*=======================================================================*/
284:            /*=======================================================================*/
285:            /*=======================================================================*/
286:
287:            /*=======================================================================*/
288:            /**
289:             * helper function to implement <code>import</code> statements.
290:             */
291:            public static Value importHelper(String path, Scope scope) {
292:                try {
293:                    AbstractFile file = OscriptInterpreter.resolve(path, false);
294:                    if (!file.exists()) {
295:                        StringBuffer sp = new StringBuffer();
296:                        for (Iterator itr = OscriptInterpreter.getScriptPath(); itr
297:                                .hasNext();) {
298:                            sp.append(itr.next());
299:                            if (itr.hasNext())
300:                                sp.append(", ");
301:                        }
302:                        throw new java.io.FileNotFoundException(path + " (in "
303:                                + sp + ")");
304:                    }
305:                    return OscriptInterpreter.eval(file, scope);
306:                } catch (Throwable e) {
307:                    throw OJavaException.makeJavaExceptionWrapper(e);
308:                }
309:            }
310:
311:            /*=======================================================================*/
312:            /**
313:             * Evaluate from the specified abstract file.  The stream is evaluated
314:             * until EOF is hit.
315:             * 
316:             * @param file         the file to evaluate
317:             * @return the result of evaluating the input
318:             * @throws ParseException if error parsing input
319:             * @throws IOException if something goes poorly when reading file
320:             */
321:            public static Value eval(AbstractFile file) throws ParseException,
322:                    IOException {
323:                return eval(file, getGlobalScope());
324:            }
325:
326:            /*=======================================================================*/
327:            /**
328:             * Evaluate from the specified abstract file.  The stream is evaluated
329:             * until EOF is hit.
330:             * 
331:             * @param file         the file to evaluate
332:             * @param scope        the scope to evaluate in
333:             * @return the result of evaluating the input
334:             * @throws ParseException if error parsing input
335:             * @throws IOException if something goes poorly when reading file
336:             */
337:            public static Value eval(AbstractFile file, Scope scope)
338:                    throws ParseException, IOException {
339:                if (TRACE_EVAL) {
340:                    long et = OscriptInterpreter.et;
341:                    long t = System.currentTimeMillis();
342:                    try {
343:                        return (Value) (StackFrame.currentStackFrame()
344:                                .evalNode(getNodeEvaluator(file), scope));
345:                    } finally {
346:                        t = System.currentTimeMillis() - t;
347:                        long total = et + t;
348:                        long cumm = t - (OscriptInterpreter.et - et);
349:                        System.err.println("eval: \t" + cumm + "\t" + t + "\t"
350:                                + total + "\t" + file.getPath());
351:                        OscriptInterpreter.et = total;
352:                    }
353:                } else {
354:                    return (Value) (StackFrame.currentStackFrame().evalNode(
355:                            getNodeEvaluator(file), scope));
356:                }
357:            }
358:
359:            public static long et;
360:
361:            /*=======================================================================*/
362:            /**
363:             * Evaluate the specified sting.
364:             * 
365:             * @param str          the string to evaluate
366:             * @return the result of evaluating the string
367:             * @throws ParseException if error parsing string
368:             */
369:            public static Value eval(String str) throws ParseException {
370:                return eval(str, getGlobalScope());
371:            }
372:
373:            // XXX fixme: work around because "eval" is a object-script keyword
374:            public static final Value __eval(String str) throws ParseException {
375:                Value val = eval(str);
376:                if (val == Value.UNDEFINED)
377:                    val = Value.NULL;
378:                return val;
379:            }
380:
381:            /*=======================================================================*/
382:            /**
383:             * Evaluate the specified sting.
384:             * 
385:             * @param str          the string to evaluate
386:             * @param scope        the scope to evaluate in
387:             * @return the result of evaluating the string
388:             * @throws ParseException if error parsing string
389:             */
390:            public static Value eval(String str, Scope scope)
391:                    throws ParseException {
392:                Node node = parse(str);
393:                NodeEvaluator ne = nodeInterpreter.createNodeEvaluator(str,
394:                        node);
395:
396:                return (Value) (StackFrame.currentStackFrame().evalNode(ne,
397:                        scope));
398:            }
399:
400:            // XXX fixme: work around because "eval" is a object-script keyword
401:            public static final Value __eval(String str, Scope scope)
402:                    throws ParseException {
403:                Value val = eval(str, scope);
404:                if (val == Value.UNDEFINED)
405:                    val = Value.NULL;
406:                return val;
407:            }
408:
409:            public static final void __declareInScope(String name, Value val,
410:                    Scope scope) {
411:                Value tmp = oscript.classwrap.ClassWrapGen.getScriptObject(val);
412:                if (tmp != null)
413:                    val = tmp;
414:                scope.createMember(name, 0).opAssign(val);
415:            }
416:
417:            /*=======================================================================*/
418:            /*=======================================================================*/
419:            /*=======================================================================*/
420:
421:            /*=======================================================================*/
422:            /**
423:             * Add the <code>parser</code> to list of recognized parsers.  The
424:             * registered parsers will determine what sorts of input the interpreter
425:             * can handle.
426:             * 
427:             * @param parser       the parser to register
428:             * @see #removeParser
429:             */
430:            public static void addParser(Parser parser) {
431:                parserList.add(parser);
432:            }
433:
434:            /*=======================================================================*/
435:            /**
436:             * Remove the <code>parser</code> from list of recognized parsers.  The
437:             * registered parsers will determine what sorts of input the interpreter
438:             * can handle.
439:             * 
440:             * @param parser       the parser to register
441:             * @see #addParser
442:             */
443:            public static void removeParser(Parser parser) {
444:                parserList.remove(parser);
445:            }
446:
447:            /*=======================================================================*/
448:            /**
449:             * Parse the input stream to a syntaxtree.
450:             * 
451:             * @param file         the file to parse
452:             * @return the parsed syntaxtree
453:             */
454:            public static Node parse(AbstractFile file) throws ParseException,
455:                    IOException {
456:                for (Iterator itr = parserList.iterator(); itr.hasNext();) {
457:                    Parser p = (Parser) (itr.next());
458:
459:                    if (p.getExtension().equals(file.getExtension()))
460:                        return p.parse(file);
461:                }
462:
463:                throw new ProgrammingErrorException("no parser for: "
464:                        + file.getPath());
465:            }
466:
467:            /**
468:             * Get node-evaluator via cache.  If not in cache, and not loadable into
469:             * cache from cache-fs, then actually parse and create new node-evaluator.
470:             * If exists in cache, but <code>file</code> has been more recently modified,
471:             * the re-parse and create new node-evaluator.
472:             */
473:            private static NodeEvaluator getNodeEvaluator(AbstractFile file)
474:                    throws ParseException, IOException {
475:                CacheEntry entry = (CacheEntry) (nodeEvaluatorCacheTable
476:                        .get(file.getPath()));
477:
478:                if (entry == null) {
479:                    AbstractFile filec = getCacheFile(file);
480:
481:                    if (filec.exists())
482:                        entry = readCacheEntry(filec);
483:
484:                    if (entry != null)
485:                        nodeEvaluatorCacheTable.put(file.getPath().intern(),
486:                                entry);
487:                }
488:
489:                if ((entry == null) || (entry.time != file.lastModified())) {
490:                    NodeEvaluator ne = createNodeEvaluator(file.getPath()
491:                            .intern(), parse(file));
492:                    entry = new CacheEntry(file, ne);
493:                    nodeEvaluatorCacheTable.put(file.getPath().intern(), entry);
494:                    writeCacheEntry(entry);
495:                }
496:
497:                return entry.ne;
498:            }
499:
500:            private static AbstractFile getCacheFile(AbstractFile file)
501:                    throws IOException {
502:                String path = file.getPath();
503:
504:                // need to sanitize path, since windoze can't deals with things like "C:"
505:                // occuring in the middle of the path:
506:                path = path.replace(':', '_');
507:
508:                return resolve("/cache/" + CACHE_VERSION + "/" + path + "c",
509:                        false);
510:            }
511:
512:            /**
513:             * this is called once at startup, to construct an empty expression
514:             * list node evaluator.
515:             */
516:            private static NodeEvaluator getEmptyExprListEvaluator()
517:                    throws IOException, ParseException {
518:                return getNodeEvaluator(resolve("__empty.os", false));
519:            }
520:
521:            static {
522:                try {
523:                    EMPTY_EXPR_LIST_EVALUATOR = getEmptyExprListEvaluator();
524:                } catch (ParseException e) {
525:                    e.printStackTrace();
526:                    throw new RuntimeException("unrecoverable error at startup");
527:                } catch (IOException e) {
528:                    e.printStackTrace();
529:                    throw new RuntimeException("unrecoverable error at startup");
530:                }
531:            }
532:
533:            /*=======================================================================*/
534:            /**
535:             * Parse the string to a syntaxtree.
536:             * 
537:             * @param str          the string to parse
538:             * @return the parsed syntaxtree
539:             */
540:            public static Node parse(String str) throws ParseException {
541:                try {
542:                    return parse(new oscript.util.InputStreamFile(
543:                            new StringBufferInputStream(str), "string-input.os"));
544:                } catch (IOException e) {
545:                    throw new ProgrammingErrorException("shouldn't get here!");
546:                }
547:            }
548:
549:            /*=======================================================================*/
550:            /*=======================================================================*/
551:            /*=======================================================================*/
552:
553:            /* I should add some mechanism to add/remove NodeEvaluatorFactory?
554:             */
555:
556:            /*=======================================================================*/
557:            /**
558:             * Create a NodeEvaluator to evaluate a node.  An application embedding
559:             * the interpreter should use this method to convert the parsed syntax
560:             * tree to something that can be evaluated within a scope, rather than
561:             * directly using the visitors.  This protects the application against
562:             * changes to the parsed representation of the program.
563:             * 
564:             * @param desc         description
565:             * @param node         the node
566:             * @return a NodeEvaluator
567:             */
568:            public static NodeEvaluator createNodeEvaluator(String name,
569:                    Node node) {
570:                // XXX hack for the cached node evaluator...
571:                NodeEvaluator ne = null;
572:
573:                if (node instanceof  Program)
574:                    ne = ((Program) node).nodeEvaluator;
575:                else if (node instanceof  FunctionCallExpressionList)
576:                    ne = ((FunctionCallExpressionList) node).nodeEvaluator;
577:                else if (node instanceof  ProgramFile)
578:                    ne = ((ProgramFile) node).nodeEvaluator;
579:
580:                if (ne != null)
581:                    return ne;
582:
583:                ne = createNodeEvaluatorImpl(name, node);
584:
585:                if (node instanceof  Program)
586:                    ((Program) node).nodeEvaluator = ne;
587:                else if (node instanceof  FunctionCallExpressionList)
588:                    ((FunctionCallExpressionList) node).nodeEvaluator = ne;
589:                else if (node instanceof  ProgramFile)
590:                    ((ProgramFile) node).nodeEvaluator = ne;
591:
592:                return ne;
593:            }
594:
595:            private static NodeEvaluator createNodeEvaluatorImpl(String name,
596:                    Node node) {
597:                NodeEvaluator ne = null;
598:
599:                if (useCompiler)
600:                    ne = nodeCompiler.createNodeEvaluator(name, node);
601:                // nodeCompiler.createNodeEvaluator could return null if compile fails
602:                // for whatever reason...
603:                if (ne == null)
604:                    ne = nodeInterpreter.createNodeEvaluator(name, node);
605:
606:                return ne;
607:            }
608:
609:            /*=======================================================================*/
610:            /*=======================================================================*/
611:            /*=======================================================================*/
612:
613:            /*=======================================================================*/
614:            /**
615:             * Add the specified path to the paths that are searched to import a
616:             * file.
617:             * 
618:             * @param path         a path to search for imports
619:             */
620:            public static void addScriptPath(String path) {
621:                try {
622:                    path = AbstractFileSystem.resolve(path).getPath(); // convert to absolute path
623:                } catch (Throwable t) {
624:                }
625:
626:                synchronized (scriptPathList) {
627:                    if (!scriptPathList.contains(path))
628:                        scriptPathList.addFirst(path);
629:                    scriptPaths = null;
630:                }
631:            }
632:
633:            /*=======================================================================*/
634:            /**
635:             * Remove the specified path to the paths that are searched to import a
636:             * file.
637:             * 
638:             * @param path         a path to search for imports
639:             */
640:            public static void removeScriptPath(String path) {
641:                try {
642:                    path = AbstractFileSystem.resolve(path).getPath(); // convert to absolute path
643:                } catch (Throwable t) {
644:                }
645:
646:                synchronized (scriptPathList) {
647:                    scriptPathList.remove(path);
648:                    scriptPaths = null;
649:                }
650:            }
651:
652:            /*=======================================================================*/
653:            /**
654:             * Return an iterator of entries in the script-path.  Each entry is a path
655:             * that is prefixed to a relative path passed to {@link #resolve} in the
656:             * process of trying to resolve a file.
657:             * 
658:             * @return an iterator of strings
659:             */
660:            public static Iterator getScriptPath() {
661:                // copy list to avoid concurrent-mod problems
662:                synchronized (scriptPathList) {
663:                    return new oscript.util.CollectionIterator((new LinkedList(
664:                            scriptPathList)).iterator());
665:                }
666:            }
667:
668:            /*=======================================================================*/
669:            /**
670:             * Try to load the specified file from one of the registered filesystems.
671:             * 
672:             * @param path         the path to the file to resolve
673:             * @param create       create the file if it does not exist
674:             * @throws IOException if something goes wrong when reading file
675:             * @see #addScriptPath
676:             */
677:            public static AbstractFile resolve(String path, boolean create)
678:                    throws IOException {
679:                AbstractFile file = resolveImpl(path);
680:
681:                // if file doesn't exist in a currently mounted filesystem, and it is 
682:                // loadable as a system resource, try to figure out what filesystem to 
683:                // mount to make it accessible:
684:                if (!file.exists()) {
685:                    if (create)
686:                        file.createNewFile();
687:                    else if ((path.charAt(0) != '/')
688:                            && tryMountSystemFileSystem(path))
689:                        file = resolveImpl(path);
690:                }
691:
692:                return file;
693:            }
694:
695:            private static AbstractFile resolveImpl(String path)
696:                    throws IOException {
697:                AbstractFile file = null;
698:
699:                if (path.charAt(0) == '/') {
700:                    file = AbstractFileSystem.resolve(path);
701:                } else {
702:                    // list should never be empty, at a minimum it should include "":
703:                    String[] scriptPaths = OscriptInterpreter.scriptPaths;
704:
705:                    // depending on how this gets compiled, order may be important
706:                    // (think other thread switching OscriptInterpreter.scriptPaths 
707:                    // back to null) so assign local copy first, just in case the 
708:                    // generated code reads the value back for the next assignment, 
709:                    // instead of just DUPing the value on the stack:
710:                    if (scriptPaths == null)
711:                        OscriptInterpreter.scriptPaths = scriptPaths = (String[]) (scriptPathList
712:                                .toArray(new String[scriptPathList.size()]));
713:
714:                    for (int i = 0; i < scriptPaths.length; i++) {
715:                        String actualPath = scriptPaths[i] + "/" + path;
716:                        file = AbstractFileSystem.resolve(actualPath);
717:                        if (file.exists())
718:                            break;
719:                    }
720:                }
721:
722:                // if file doesn't exist, always return the non-existant file with
723:                // absolute path, so if the user wants to create the file, it gets
724:                // created with the specified absolute path, rather than relative
725:                // to the last entry in the script-path:
726:                if (!file.exists())
727:                    file = AbstractFileSystem.resolve(path);
728:
729:                return file;
730:            }
731:
732:            /**
733:             * Mount a .jar file under <code>/jar/file.jar</code> and add to script path
734:             * @param file   the jar file to mount
735:             */
736:            public static final void mountJarFile(AbstractFile file)
737:                    throws Exception {
738:                mountJarFile(file, true);
739:            }
740:
741:            private static final void mountJarFile(AbstractFile file,
742:                    boolean addToClassPath) throws Exception {
743:                String vpath = "/jar/" + file.getName();
744:                vpath = vpath.substring(0, vpath.length() - 4); // get rid of ".jar"
745:                AbstractFileSystem.mount(new JarFileSystem((File) file, true),
746:                        vpath);
747:                addScriptPath(vpath);
748:                if (addToClassPath && (file instanceof  File)) {
749:                    registerClassLoader(new URLClassLoader(
750:                            new URL[] { ((File) file).toURL() }, ClassLoader
751:                                    .getSystemClassLoader()));
752:                }
753:            }
754:
755:            /**
756:             * hack to try an load something as a system resource, and if possible
757:             * parse the URL to try and figure out the jar file or local-file-
758:             * system path to mount into the abstract file system.
759:             */
760:            private static final boolean tryMountSystemFileSystem(String path) {
761:                try {
762:                    URL url = classLoader.getResource(path);
763:                    if (url != null) {
764:                        url = oscript.util.ResourceResolver.resolve(url);
765:                        String urlStr = url.toExternalForm();
766:                        String filePath;
767:
768:                        if ((filePath = getJarFilePath(path, urlStr)) != null) {
769:                            // figure out name of jar file, which determines where it is to be mounted:
770:                            int idx1 = filePath.lastIndexOf('/');
771:                            idx1 = (idx1 != -1) ? idx1 : filePath
772:                                    .lastIndexOf('\"');
773:                            idx1 = (idx1 != -1) ? idx1 : 0;
774:                            int idx2 = filePath.lastIndexOf(".jar");
775:                            idx2 = (idx2 != -1) ? idx2 : filePath.length();
776:
777:                            String name = filePath.substring(idx1 + 1, idx2);
778:
779:                            // work around for the name mangling by webstart:
780:                            if (name.startsWith("RM")
781:                                    && (idx1 >= 8)
782:                                    && filePath.substring(idx1 - 8, idx1)
783:                                            .equals("DMsigned"))
784:                                name = name.substring(2);
785:
786:                            mountJarFile(AbstractFileSystem.resolve(filePath),
787:                                    false);
788:
789:                            return true;
790:                        }
791:
792:                        if ((filePath = getFilePath(path, urlStr)) != null) {
793:                            // figure out name of the directory, which determines where it is to be mounted:
794:                            int idx1 = filePath.lastIndexOf('/');
795:                            idx1 = (idx1 != -1) ? idx1 : filePath
796:                                    .lastIndexOf('\"');
797:                            idx1 = (idx1 != -1) ? idx1 : 0;
798:                            String vpath = "/file/" + filePath.substring(idx1);
799:
800:                            LocalFileSystem.mount(
801:                                    new LocalFileSystem(filePath), vpath);
802:                            addScriptPath(vpath);
803:                            return true;
804:                        }
805:                    }
806:                } catch (Throwable t) {
807:                    t.printStackTrace();
808:                }
809:
810:                return false;
811:            }
812:
813:            private static final String getJarFilePath(String path,
814:                    String urlStr) {
815:                if (urlStr.startsWith("jar:file:")) {
816:                    int idx = urlStr.lastIndexOf('!');
817:
818:                    if (idx != -1)
819:                        return sanitizeUrl(urlStr.substring("jar:file:"
820:                                .length(), idx));
821:                }
822:                return null;
823:            }
824:
825:            private static final String getFilePath(String path, String urlStr) {
826:                if (urlStr.startsWith("file:")) {
827:                    int idx = urlStr.lastIndexOf(path);
828:
829:                    if (idx != -1)
830:                        return sanitizeUrl(urlStr.substring("file:".length(),
831:                                idx));
832:                }
833:                return null;
834:            }
835:
836:            /**
837:             * utility to string out "%20" and other escape codes, and replace them
838:             * with the appropriate character.
839:             */
840:            private static final String sanitizeUrl(String str) {
841:                int lastIdx = 0;
842:                int idx;
843:
844:                str = str.replace('\\', '/');
845:
846:                while ((idx = str.indexOf('%', lastIdx)) != -1) {
847:                    String a = str.substring(0, idx);
848:                    String b = str.substring(idx + 3);
849:                    String hex = str.substring(idx + 1, idx + 3);
850:
851:                    char c = (char) (Integer.parseInt(hex, 16));
852:
853:                    str = a + c + b;
854:
855:                    lastIdx = idx;
856:                }
857:
858:                return str;
859:            }
860:
861:            /*=======================================================================*/
862:            /*=======================================================================*/
863:            /*=======================================================================*/
864:
865:            private static CacheEntry readCacheEntry(AbstractFile filec)
866:                    throws IOException {
867:                CacheEntry entry = new CacheEntry();
868:
869:                InputStream is = new BufferedInputStream(filec.getInputStream());
870:                ObjectInputStream ois = new ObjectInputStream(is) {
871:
872:                    protected Class resolveClass(ObjectStreamClass v)
873:                            throws IOException, ClassNotFoundException {
874:                        return CompilerClassLoader.forName(v.getName(), false,
875:                                cacheClassLoader);
876:                    }
877:
878:                };
879:
880:                try {
881:                    entry.readExternal(ois);
882:                } catch (ClassNotFoundException e) {
883:                    e.printStackTrace();
884:                    System.exit(-1);
885:                }
886:
887:                return entry;
888:            }
889:
890:            private static void writeCacheEntry(CacheEntry entry)
891:                    throws IOException {
892:                AbstractFile filec = getCacheFile(entry.file);
893:
894:                if (!filec.exists())
895:                    filec.createNewFile();
896:
897:                OutputStream os = filec.getOutputStream(false);
898:                ObjectOutputStream oos = new ObjectOutputStream(
899:                        new BufferedOutputStream(os));
900:
901:                entry.writeExternal(oos);
902:                oos.flush();
903:                oos.close();
904:            }
905:
906:            /**
907:             * An entry in the node-evaluator cache.
908:             * 
909:             * @see #getNodeEntry
910:             */
911:            public static class CacheEntry {
912:                public transient AbstractFile file;
913:                public long time;
914:                public NodeEvaluator ne;
915:
916:                public CacheEntry() {
917:                }
918:
919:                public void readExternal(ObjectInput in)
920:                        throws ClassNotFoundException, IOException {
921:                    time = in.readLong();
922:                    if (in.readByte() == 1) {
923:                        Class c = Class.forName(in.readUTF(), false,
924:                                cacheClassLoader);
925:                        try {
926:                            ne = (NodeEvaluator) (c.newInstance());
927:                        } catch (Throwable e) {
928:                            e.printStackTrace();
929:                            System.exit(-1);
930:                        }
931:                    }
932:                }
933:
934:                public void writeExternal(ObjectOutput out) throws IOException {
935:                    out.writeLong(time);
936:                    if (ne instanceof  CompiledNodeEvaluator) {
937:                        out.writeByte(1);
938:                        out.writeUTF(ne.getClass().getName());
939:                    } else {
940:                        out.writeByte(0);
941:                    }
942:                }
943:
944:                CacheEntry(AbstractFile file, NodeEvaluator ne) {
945:                    this .file = file;
946:                    this .time = file.lastModified();
947:                    this .ne = ne;
948:                }
949:
950:                public String toString() {
951:                    return "<time: " + time + ", ne: " + ne + ">";
952:                }
953:            }
954:        }
955:
956:        /*
957:         *   Local Variables:
958:         *   tab-width: 2
959:         *   indent-tabs-mode: nil
960:         *   mode: java
961:         *   c-indentation-style: java
962:         *   c-basic-offset: 2
963:         *   eval: (c-set-offset 'substatement-open '0)
964:         *   eval: (c-set-offset 'case-label '+)
965:         *   eval: (c-set-offset 'inclass '+)
966:         *   eval: (c-set-offset 'inline-open '0)
967:         *   End:
968:         */
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.