Source Code Cross Referenced for Script.java in  » Testing » abbot-1.0.1 » abbot » script » 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 » abbot 1.0.1 » abbot.script 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package abbot.script;
002:
003:        import java.awt.Component;
004:        import java.io.*;
005:        import java.net.URL;
006:        import java.util.*;
007:
008:        import org.jdom.*;
009:        import org.jdom.input.SAXBuilder;
010:        import org.jdom.output.XMLOutputter;
011:        import org.jdom.output.Format;
012:
013:        import abbot.Log;
014:        import abbot.Platform;
015:        import abbot.finder.*;
016:        import abbot.i18n.Strings;
017:        import abbot.script.parsers.*;
018:        import abbot.tester.Robot;
019:        import abbot.util.Properties;
020:
021:        /**
022:         * Provide a structure to encapsulate actions invoked on GUI components and
023:         * tests performed on those components.  Scripts need to be short and concise
024:         * (and therefore easy to read/write). Extensions don't have to be.<p> 
025:         * This takes a single filename as a constructor argument.<p>
026:         * Use {@link junit.extensions.abbot.ScriptFixture} and
027:         * {@link junit.extensions.abbot.ScriptTestSuite}
028:         * to generate a suite by auto-generating a collection of {@link Script}s.<p>
029:         * @see StepRunner  
030:         * @see Fixture
031:         * @see Launch
032:         */
033:
034:        public class Script extends Sequence implements  Resolver {
035:            public static final String INTERPRETER = "bsh";
036:            private static final String USAGE = "<AWTTestScript [desc=\"\"] [forked=\"true\"] [slow=\"true\"]"
037:                    + " [awt=\"true\"] [vmargs=\"...\"]>...</AWTTestScript>\n";
038:
039:            /** Robot delay for slow playback.  */
040:            private static int slowDelay = 250;
041:            static boolean validate = true;
042:            private String filename;
043:            private File relativeDirectory;
044:            private boolean fork;
045:            private boolean slow;
046:            private boolean awt;
047:            private int lastSaved;
048:            private String vmargs;
049:            private Map properties = new HashMap();
050:            private Hierarchy hierarchy;
051:            public static final String UNTITLED_FILE = Strings
052:                    .get("script.untitled_filename");
053:            protected static final String UNTITLED = Strings
054:                    .get("script.untitled");
055:
056:            /** Read-only map of ref IDs into ComponentReferences. */
057:            private Map refs = Collections.unmodifiableMap(new HashMap());
058:            /** Maps components to references.  This cache provides a 20% speedup when
059:             * adding new references.
060:             */
061:            private Map components = new WeakHashMap();
062:
063:            static {
064:                slowDelay = Properties.getProperty("abbot.script.slow_delay",
065:                        slowDelay, 0, 60000);
066:                String defValue = Platform.JAVA_VERSION < Platform.JAVA_1_4 ? "false"
067:                        : "true";
068:                validate = "true".equals(System.getProperty(
069:                        "abbot.script.validate", defValue));
070:            }
071:
072:            protected static Map createDefaultMap(String filename) {
073:                Map map = new HashMap();
074:                map.put(TAG_FILENAME, filename);
075:                return map;
076:            }
077:
078:            /** Create a new, empty <code>Script</code>.  Used as a temporary
079:             * {@link Resolver}, uses the default {@link Hierarchy}.
080:             * @deprecated Use an explicit {@link Hierarchy} instead.
081:             */
082:            public Script() {
083:                // This is roughly equivalent to what
084:                // DefaultComponentFinder.getFinder() used to do
085:                this (AWTHierarchy.getDefault());
086:            }
087:
088:            /** Create a <code>Script</code> from the given filename.  Uses the
089:                default {@link Hierarchy}.  
090:                @deprecated Use an explicit {@link Hierarchy} instead.
091:             */
092:            public Script(String filename) {
093:                // This is roughly equivalent to what
094:                // DefaultComponentFinder.getFinder() used to do
095:                this (filename, AWTHierarchy.getDefault());
096:            }
097:
098:            public Script(Hierarchy h) {
099:                this (null, new HashMap());
100:                setHierarchy(h);
101:            }
102:
103:            /** Create a <code>Script</code> from the given file.  */
104:            public Script(String filename, Hierarchy h) {
105:                this (null, createDefaultMap(filename));
106:                setHierarchy(h);
107:            }
108:
109:            public Script(Resolver parent, Map attributes) {
110:                super (parent, attributes);
111:                String filename = (String) attributes.get(TAG_FILENAME);
112:                File file = filename != null ? new File(filename)
113:                        : getTempFile(parent != null ? parent.getDirectory()
114:                                : null);
115:
116:                // If this file is not absolute setFile is going to convert to a connoical
117:                // path so we actually need this to be relative to the parent
118:                //
119:
120:                if (!file.isAbsolute()) {
121:                    file = new File(parent.getDirectory(), filename);
122:                }
123:
124:                // Configure the file
125:                //
126:
127:                setFile(file);
128:                if (parent != null) {
129:                    setRelativeTo(parent.getDirectory());
130:                }
131:                try {
132:                    load();
133:                } catch (IOException e) {
134:                    setScriptError(e);
135:                }
136:            }
137:
138:            /** Since we allow ComponentReference IDs to be changed, make sure our map
139:             * is always up to date.
140:             */
141:            private synchronized void synchReferenceIDs() {
142:                HashMap map = new HashMap();
143:                Iterator iter = refs.values().iterator();
144:                while (iter.hasNext()) {
145:                    ComponentReference ref = (ComponentReference) iter.next();
146:                    map.put(ref.getID(), ref);
147:                }
148:                if (!refs.equals(map)) {
149:                    // atomic update of references map
150:                    refs = Collections.unmodifiableMap(map);
151:                }
152:            }
153:
154:            public void setHierarchy(Hierarchy h) {
155:                hierarchy = h;
156:                components.clear();
157:            }
158:
159:            private File getTempFile(File dir) {
160:                File file;
161:                try {
162:                    file = (dir != null ? File.createTempFile(UNTITLED_FILE,
163:                            ".xml", dir) : File.createTempFile(UNTITLED_FILE,
164:                            ".xml"));
165:                    // We don't actually need the file on disk
166:                    file.delete();
167:                } catch (IOException io) {
168:                    file = (dir != null ? new File(dir, UNTITLED_FILE + ".xml")
169:                            : new File(UNTITLED_FILE + ".xml"));
170:                }
171:                return file;
172:            }
173:
174:            public String getName() {
175:                return filename;
176:            }
177:
178:            public void setForked(boolean fork) {
179:                this .fork = fork;
180:            }
181:
182:            public boolean isForked() {
183:                return fork;
184:            }
185:
186:            public void setVMArgs(String args) {
187:                if (args != null && "".equals(args))
188:                    args = null;
189:                vmargs = args;
190:            }
191:
192:            public String getVMArgs() {
193:                return vmargs;
194:            }
195:
196:            public boolean isSlowPlayback() {
197:                return slow;
198:            }
199:
200:            public void setSlowPlayback(boolean slow) {
201:                this .slow = slow;
202:            }
203:
204:            public boolean isAWTMode() {
205:                return awt;
206:            }
207:
208:            public void setAWTMode(boolean awt) {
209:                this .awt = awt;
210:            }
211:
212:            /** Return the file where this script is saved.  Will always be an
213:             * absolute path.
214:             */
215:            public File getFile() {
216:                File file = new File(filename);
217:                if (!file.isAbsolute()) {
218:                    String path = getRelativeTo().getPath() + File.separator
219:                            + filename;
220:                    file = new File(path);
221:                    file = resolveRelativeReferences(file);
222:                }
223:                return file;
224:            }
225:
226:            /** Change the file system basis for the current script.  Does not affect
227:                the script contents.
228:                @deprecated Use {@link #setFile(File)}.
229:             */
230:            public void changeFile(File file) {
231:                setFile(file);
232:            }
233:
234:            /** Set the file system basis for this script object.  Use this to set the
235:                file from which the existing script will be loaded.
236:             */
237:            public void setFile(File file) {
238:                Log.debug("Script file set to " + file);
239:                if (file == null)
240:                    throw new IllegalArgumentException("File must not be null");
241:                if (filename == null || !file.equals(getFile())) {
242:
243:                    // Convert to full absolute version 
244:                    //
245:
246:                    file = resolveRelativeReferences(file);
247:                    filename = file.getPath();
248:
249:                    Log.debug("Script filename set to " + filename);
250:                    if (relativeDirectory != null)
251:                        setRelativeTo(relativeDirectory);
252:                }
253:                lastSaved = getHash() + 1;
254:            }
255:
256:            /** Typical xml header, so we can know about how much file prefix to
257:             * skip.
258:             */
259:            private static final String XML_INFO = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
260:
261:            /** Flag to indicate whether emitted XML should contain the script
262:                contents.  Sometimes we just want a one-liner (like when displaying in
263:                the script editor), and sometimes we want the full contents (when
264:                writing to file).
265:             */
266:            private boolean formatForSave = false;
267:
268:            /** Write the current state of the script to file. */
269:            public void save(Writer writer) throws IOException {
270:                formatForSave = true;
271:                Element el = toXML();
272:                formatForSave = false;
273:                el.setName(TAG_AWTTESTSCRIPT);
274:
275:                Document doc = new Document(el);
276:                XMLOutputter outputter = new XMLOutputter(Format
277:                        .getPrettyFormat());
278:                outputter.output(doc, writer);
279:            }
280:
281:            /** Only thing directly editable on a script is its file path. */
282:            public String toEditableString() {
283:                return getFilename();
284:            }
285:
286:            /** Has this script changed since the last save. */
287:            public boolean isDirty() {
288:                return getHash() != lastSaved;
289:            }
290:
291:            /** Write the script to file.  Note that this differs from the toXML for
292:                the script, which simply indicates the file on which it is based. */
293:            public void save() throws IOException {
294:                File file = getFile();
295:                Log.debug("Saving script to '" + file + "' " + hashCode());
296:                OutputStreamWriter writer = new OutputStreamWriter(
297:                        new FileOutputStream(file), "UTF-8");
298:                save(new BufferedWriter(writer));
299:                writer.close();
300:                lastSaved = getHash();
301:            }
302:
303:            /** Ensure that all referenced components are actually in the components
304:             * list.
305:             */
306:            private synchronized void verify() throws InvalidScriptException {
307:                Log.debug("verifying all referenced refs exist");
308:                Iterator iter = refs.values().iterator();
309:                while (iter.hasNext()) {
310:                    ComponentReference ref = (ComponentReference) iter.next();
311:                    String id = ref.getAttribute(TAG_PARENT);
312:                    if (id != null && refs.get(id) == null) {
313:                        String msg = Strings.get("script.parent_missing",
314:                                new Object[] { id });
315:                        throw new InvalidScriptException(msg);
316:                    }
317:                    id = ref.getAttribute(TAG_WINDOW);
318:                    if (id != null && refs.get(id) == null) {
319:                        String msg = Strings.get("script.window_missing",
320:                                new Object[] { id });
321:                        throw new InvalidScriptException(msg);
322:                    }
323:                }
324:            }
325:
326:            /** Make the path to the given child script relative to this one. */
327:            private void updateRelativePath(Step child) {
328:                // Make sure included scripts are located relative to this one
329:                if (child instanceof  Script) {
330:                    ((Script) child).setRelativeTo(getDirectory());
331:                }
332:            }
333:
334:            protected void parseChild(Element el) throws InvalidScriptException {
335:                if (el.getName().equals(TAG_COMPONENT)) {
336:                    addComponentReference(el);
337:                } else {
338:                    synchronized (steps()) {
339:                        super .parseChild(el);
340:                        updateRelativePath((Step) steps().get(size() - 1));
341:                    }
342:                }
343:            }
344:
345:            /** Parse XML attributes for the Script. */
346:            protected void parseAttributes(Map map) {
347:                parseStepAttributes(map);
348:                fork = Boolean.valueOf((String) map.get(TAG_FORKED))
349:                        .booleanValue();
350:                slow = Boolean.valueOf((String) map.get(TAG_SLOW))
351:                        .booleanValue();
352:                awt = Boolean.valueOf((String) map.get(TAG_AWT)).booleanValue();
353:                vmargs = (String) map.get(TAG_VMARGS);
354:            }
355:
356:            /** Loads the XML test script.  Performs a check against the XML schema.
357:                @param reader Provides the script data
358:                @throws InvalidScriptException
359:                @throws IOException
360:             */
361:            public void load(Reader reader) throws InvalidScriptException,
362:                    IOException {
363:                clear();
364:                try {
365:                    // Set things up to optionally validate on load
366:                    SAXBuilder builder = new SAXBuilder(validate);
367:                    if (validate) {
368:                        URL url = getClass().getClassLoader().getResource(
369:                                "abbot/abbot.xsd");
370:                        if (url != null) {
371:                            builder
372:                                    .setFeature(
373:                                            "http://apache.org/xml/features/validation/schema",
374:                                            true);
375:                            builder
376:                                    .setProperty(
377:                                            "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation",
378:                                            url.toString());
379:                        } else {
380:                            Log
381:                                    .warn("Could not find abbot/abbot.xsd, disabling XML validation");
382:                            validate = false;
383:                        }
384:                    }
385:                    Document doc = builder.build(reader);
386:                    Element root = doc.getRootElement();
387:                    Map map = createAttributeMap(root);
388:                    parseAttributes(map);
389:                    parseChildren(root);
390:                } catch (JDOMException e) {
391:                    throw new InvalidScriptException(e.getMessage());
392:                }
393:                // Make sure we have all referenced components
394:                synchronized (this ) {
395:                    synchReferenceIDs();
396:                    verify();
397:                }
398:                lastSaved = getHash();
399:            }
400:
401:            public void addStep(int index, Step step) {
402:                super .addStep(index, step);
403:                updateRelativePath(step);
404:            }
405:
406:            public void addStep(Step step) {
407:                super .addStep(step);
408:                updateRelativePath(step);
409:            }
410:
411:            /** Replaces the step at the given index. */
412:            public void setStep(int index, Step step) {
413:                super .setStep(index, step);
414:                updateRelativePath(step);
415:            }
416:
417:            /** Read the script from the currently set file.  */
418:            public void load() throws IOException {
419:                File file = getFile();
420:                if (!file.exists()) {
421:                    if (getFilename().indexOf(Script.UNTITLED_FILE) == -1)
422:                        Log.warn("Script " + this 
423:                                + " does not exist, ignoring it");
424:                    return;
425:                }
426:                if (!file.isFile())
427:                    throw new InvalidScriptException("Path " + getFilename()
428:                            + " refers to a directory");
429:                if (file.length() != 0) {
430:                    try {
431:                        Reader reader = new InputStreamReader(
432:                                new FileInputStream(file), "UTF-8");
433:                        try {
434:                            load(new BufferedReader(reader));
435:                        } finally {
436:                            try {
437:                                reader.close();
438:                            } catch (IOException e) {
439:                            }
440:                        }
441:                    } catch (FileNotFoundException e) {
442:                        // should have been detected
443:                        Log.warn("File '" + file + "' exists but is not found");
444:                    }
445:                } else {
446:                    Log.warn("Script file " + this  + " is empty");
447:                }
448:            }
449:
450:            protected String getFullXMLString() {
451:                try {
452:                    formatForSave = true;
453:                    return toXMLString(this );
454:                } finally {
455:                    formatForSave = false;
456:                }
457:            }
458:
459:            private int getHash() {
460:                return getFullXMLString().hashCode();
461:            }
462:
463:            public String getXMLTag() {
464:                return TAG_SCRIPT;
465:            }
466:
467:            /** Save component references in addition to everything else. */
468:            public Element addContent(Element el) {
469:                // Only save content if writing to disk
470:                if (formatForSave) {
471:                    synchReferenceIDs();
472:                    Iterator iter = new TreeSet(refs.values()).iterator();
473:                    while (iter.hasNext()) {
474:                        ComponentReference cref = (ComponentReference) iter
475:                                .next();
476:                        el.addContent(cref.toXML());
477:                    }
478:                    // Now collect our child steps
479:                    return super .addContent(el);
480:                }
481:                return el;
482:            }
483:
484:            /** Return the (possibly relative) path to this script. */
485:            public String getFilename() {
486:                return filename;
487:            }
488:
489:            /** Provide XML attributes for this Step.  This class adds its filename. */
490:            public Map getAttributes() {
491:                Map map;
492:                if (!formatForSave) {
493:                    map = new HashMap();
494:
495:                    // Ensure that any relative references are using
496:                    // forward slashed for multiplatform compatibility.
497:
498:                    String f = getFilename();
499:                    if (f != null && !new File(f).isAbsolute()) {
500:                        f = f.replace('\\', '/');
501:                    }
502:
503:                    map.put(TAG_FILENAME, f);
504:                } else {
505:                    map = super .getAttributes();
506:                    // default is no fork
507:                    if (fork) {
508:                        map.put(TAG_FORKED, "true");
509:                        if (vmargs != null) {
510:                            map.put(TAG_VMARGS, vmargs);
511:                        }
512:                    }
513:                    if (slow) {
514:                        map.put(TAG_SLOW, "true");
515:                    }
516:                    if (awt) {
517:                        map.put(TAG_AWT, "true");
518:                    }
519:                }
520:                return map;
521:            }
522:
523:            protected void runStep(StepRunner runner) throws Throwable {
524:                components.clear();
525:                properties.clear();
526:                // Make all files relative to this script
527:                Parser fc = new FileParser() {
528:                    public String relativeTo() {
529:                        Log.debug("All file references will be relative to "
530:                                + getDirectory().getAbsolutePath());
531:                        return getDirectory().getAbsolutePath();
532:                    }
533:                };
534:                Parser oldfc = ArgumentParser.setParser(File.class, fc);
535:                int oldDelay = Robot.getAutoDelay();
536:                int oldMode = Robot.getEventMode();
537:                if (slow) {
538:                    Robot.setAutoDelay(slowDelay);
539:                }
540:                if (awt) {
541:                    Robot.setEventMode(Robot.EM_AWT);
542:                }
543:
544:                try {
545:                    super .runStep(runner);
546:                } finally {
547:                    Robot.setAutoDelay(oldDelay);
548:                    Robot.setEventMode(oldMode);
549:                    ArgumentParser.setParser(File.class, oldfc);
550:                }
551:            }
552:
553:            /** Set up a blank script, discarding any current state. */
554:            public void clear() {
555:                setScriptError(null);
556:                refs = Collections.unmodifiableMap(new HashMap());
557:                components.clear();
558:                super .clear();
559:            }
560:
561:            public String getUsage() {
562:                return USAGE;
563:            }
564:
565:            /** Return a default description for this <code>Script</code>. */
566:            public String getDefaultDescription() {
567:                String ext = fork ? " &" : "";
568:                String desc = Strings.get("script.desc", new Object[] {
569:                        getFilename(), ext });
570:                return desc.indexOf(UNTITLED_FILE) != -1 ? UNTITLED : desc;
571:            }
572:
573:            /** Return whether this <code>Script</code> is launchable. */
574:            public boolean hasLaunch() {
575:                // First step might be a Launch or a Fixture
576:                return size() > 0
577:                        && (((Step) steps().get(0)) instanceof  UIContext);
578:            }
579:
580:            /** @return The {@link UIContext} responsible for setting up
581:             * a UI context for this script, or
582:             * <code>null</code> if the script has no UI to speak of.
583:             */
584:            public UIContext getUIContext() {
585:                synchronized (steps()) {
586:                    if (hasLaunch()) {
587:                        return (UIContext) steps().get(0);
588:                    }
589:                }
590:                return null;
591:            }
592:
593:            /** Defer to the {@link UIContext} to obtain a 
594:             * {@link ClassLoader}, or use the current {@link Thread}'s
595:             * context class loader.
596:             * @see Thread#getContextClassLoader()
597:             */
598:            public ClassLoader getContextClassLoader() {
599:                UIContext context = getUIContext();
600:                return context != null ? context.getContextClassLoader()
601:                        : Thread.currentThread().getContextClassLoader();
602:            }
603:
604:            public boolean hasTerminate() {
605:                return size() > 0
606:                        && (((Step) steps().get(size() - 1)) instanceof  Terminate);
607:            }
608:
609:            /** By default, all pathnames are relative to the current working
610:                directory.
611:             */
612:            public File getRelativeTo() {
613:                if (relativeDirectory == null)
614:                    return new File(System.getProperty("user.dir"));
615:                return relativeDirectory;
616:            }
617:
618:            /** Indicate that when invoking toXML, a path relative to the given one
619:             * should be shown.  Note that this is a runtime setting only and never
620:             * shows up in saved XML.
621:             */
622:            public void setRelativeTo(File dir) {
623:                Log.debug("Want relative dir " + dir);
624:
625:                // If the old relatative directory is not null then convert the
626:                // filename back to a non relative path
627:                //
628:
629:                if (relativeDirectory != null) {
630:
631:                    File file = new File(filename);
632:                    if (!file.isAbsolute()) {
633:
634:                        file = new File(relativeDirectory, filename);
635:                        try {
636:                            filename = file.getCanonicalPath();
637:                        } catch (IOException ioe) {
638:                            filename = file.getPath();
639:                        }
640:                    }
641:                }
642:
643:                //
644:
645:                relativeDirectory = dir;
646:                if (dir != null) {
647:
648:                    // More robust relative path examples
649:
650:                    File currentParent = resolveRelativeReferences(dir);
651:
652:                    StringBuffer relativePath = new StringBuffer();
653:                    searchParents: do {
654:
655:                        String relPath = currentParent.getAbsolutePath();
656:                        if (filename.startsWith(relPath)
657:                                && relPath.length() < filename.length()) {
658:                            char ch = filename.charAt(relPath.length());
659:                            if (ch == '/' || ch == '\\') {
660:
661:                                // We have found a match
662:
663:                                relativePath.append(filename.substring(relPath
664:                                        .length() + 1));
665:                                filename = relativePath.toString().replace(
666:                                        '\\', '/');
667:                                break searchParents;
668:                            }
669:                        }
670:
671:                        // Do the loop again
672:                        //
673:
674:                        currentParent = currentParent.getParentFile();
675:                        relativePath.append("../");
676:
677:                    } while (currentParent != null);
678:
679:                }
680:                Log.debug("Relative dir set to " + relativeDirectory + " for "
681:                        + this );
682:            }
683:
684:            /**
685:             * It turns out that getAbsolutePath doesn't remove any relative path
686:             * entries such as .. the alternative getCannonicalPath can cause problems
687:             * with version control systems that make a lot of use of symolic links.
688:             * For example a directory in a source control view might contain local
689:             * checked out files and symlinks to un-checked out files (These files 
690:             * might be located on another machine in some cases). This means that 
691:             * files that are next to each other in the view appear to be in quite
692:             * different  paths when resolved using getCannonicalPath. Therefore we are 
693:             * reduced to tidying up the paths manually.
694:             * 
695:             * @param file The input file to tidy up.
696:             * @return An absolute path with all . and .. removed
697:             * @throws IllegalArgumentException If the number of ".." entries outnumber
698:             *   those of the normal path entries.
699:             */
700:
701:            public static File resolveRelativeReferences(File file) {
702:
703:                StringBuffer fixAbsolutePath = new StringBuffer();
704:                String originalPath = file.getAbsolutePath();
705:                String parts[] = originalPath.split("(\\\\|/)");
706:
707:                // Work backwards
708:                //
709:
710:                int dirDebt = 0;
711:                for (int i = parts.length - 1; i >= 0; i--) {
712:                    String part = parts[i];
713:                    if (part.length() == 0) {
714:                        ; // ignore this
715:                    } else if (".".equals(part)) {
716:                        ; // ignore dot paths
717:                    } else if ("..".equals(part)) {
718:                        dirDebt++; // Record an path we have to run out
719:                    } else {
720:                        if (dirDebt > 0) {
721:                            dirDebt--;
722:                        } else {
723:                            fixAbsolutePath.insert(0, part);
724:                            fixAbsolutePath.insert(0, File.separatorChar);
725:                        }
726:                    }
727:                }
728:
729:                if (dirDebt > 0) {
730:                    throw new IllegalArgumentException("Run out of path");
731:                }
732:
733:                return new File(fixAbsolutePath.toString());
734:            }
735:
736:            /** Return whether the given file looks like a valid AWT script. */
737:            public static boolean isScript(File file) {
738:                if (file.length() == 0)
739:                    return true;
740:                if (!file.exists() || !file.isFile()
741:                        || file.length() < TAG_AWTTESTSCRIPT.length() * 2 + 5)
742:                    return false;
743:                InputStream is = null;
744:                try {
745:                    int len = XML_INFO.length() + TAG_AWTTESTSCRIPT.length()
746:                            + 15;
747:                    is = new BufferedInputStream(new FileInputStream(file));
748:                    byte[] buf = new byte[len];
749:                    is.read(buf, 0, buf.length);
750:                    String str = new String(buf, 0, buf.length);
751:                    return str.indexOf(TAG_AWTTESTSCRIPT) != -1;
752:                } catch (Exception exc) {
753:                    return false;
754:                } finally {
755:                    if (is != null)
756:                        try {
757:                            is.close();
758:                        } catch (Exception exc) {
759:                        }
760:                }
761:            }
762:
763:            /** All relative files should be accessed relative to this directory,
764:                which is the directory where the script resides.
765:                It will always return an absolute path.
766:             */
767:            public File getDirectory() {
768:                return getFile().getParentFile();
769:            }
770:
771:            /** Returns a sorted collection of ComponentReferences. */
772:            public Collection getComponentReferences() {
773:                return new TreeSet(refs.values());
774:            }
775:
776:            /** Add a component reference directly, replacing any existing one with
777:                the same ID.
778:             */
779:            public void addComponentReference(ComponentReference ref) {
780:                Log.debug("adding " + ref);
781:                synchReferenceIDs();
782:                HashMap map = new HashMap(refs);
783:                map.put(ref.getID(), ref);
784:                // atomic update of references map
785:                refs = Collections.unmodifiableMap(map);
786:            }
787:
788:            /** Add a new component reference for the given component. */
789:            // FIXME: a repaint (tree locked) which accesses the refs list
790:            // deadlocks with cref creation (locks refs, asks for tree lock)
791:            // Either get tree lock first or don't require refs lock on read
792:            public ComponentReference addComponent(Component comp) {
793:                synchReferenceIDs();
794:                Log.debug("look up existing for " + Robot.toString(comp));
795:                Map newRefs = new HashMap();
796:                ComponentReference ref = ComponentReference.getReference(this ,
797:                        comp, newRefs);
798:                Log.debug("adding " + Robot.toString(comp));
799:                Map map = new HashMap(refs);
800:                map.putAll(newRefs);
801:                Iterator iter = newRefs.values().iterator();
802:                while (iter.hasNext()) {
803:                    ComponentReference r = (ComponentReference) iter.next();
804:                    Component c = r.getCachedLookup(getHierarchy());
805:                    if (c != null)
806:                        components.put(c, r);
807:                }
808:                // atomic update of references map
809:                refs = Collections.unmodifiableMap(map);
810:                return ref;
811:            }
812:
813:            /** Add a new component reference to the script.  For use only when
814:             * parsing a script.
815:             */
816:            ComponentReference addComponentReference(Element el)
817:                    throws InvalidScriptException {
818:                synchReferenceIDs();
819:                ComponentReference ref = new ComponentReference(this , el);
820:                Log.debug("adding " + el);
821:                Map map = new HashMap(refs);
822:                map.put(ref.getID(), ref);
823:                // atomic update of references map
824:                refs = Collections.unmodifiableMap(map);
825:                return ref;
826:            }
827:
828:            /** Return the reference for the given component, or null if none yet
829:             * exists. 
830:             */
831:            public ComponentReference getComponentReference(Component comp) {
832:                if (!getHierarchy().contains(comp)) {
833:                    String msg = Strings.get("script.not_in_hierarchy",
834:                            new Object[] { comp.toString() });
835:                    throw new IllegalArgumentException(msg);
836:                }
837:                synchReferenceIDs();
838:                // Clear the component map if any one of the mappings is invalid
839:                Iterator iter = refs.values().iterator();
840:                while (iter.hasNext()) {
841:                    ComponentReference cr = (ComponentReference) iter.next();
842:                    if (cr.getCachedLookup(getHierarchy()) == null) {
843:                        components.clear();
844:                        break;
845:                    }
846:                }
847:                ComponentReference ref = (ComponentReference) components
848:                        .get(comp);
849:                if (ref != null) {
850:                    if (ref.getCachedLookup(getHierarchy()) != null)
851:                        return ref;
852:                    components.remove(comp);
853:                }
854:                ref = ComponentReference.matchExisting(comp, refs.values());
855:                if (ref != null) {
856:                    components.put(comp, ref);
857:                }
858:                return ref;
859:            }
860:
861:            /** Convert the given reference ID into a component reference.  If it's
862:             * not in the Script's list, returns null.
863:             */
864:            public ComponentReference getComponentReference(String name) {
865:                synchReferenceIDs();
866:                return (ComponentReference) refs.get(name);
867:            }
868:
869:            public void setProperty(String name, Object value) {
870:                if (value == null)
871:                    properties.remove(name);
872:                else
873:                    properties.put(name, value);
874:            }
875:
876:            public Object getProperty(String name) {
877:                Object value = properties.get(name);
878:                // Lazy-load the interpreter, so it's only instantiated when required
879:                if (value == null && INTERPRETER.equals(name)) {
880:                    Interpreter bsh = new Interpreter(this );
881:                    properties.put(name, value = bsh);
882:                }
883:                return value;
884:            }
885:
886:            /** Return the currently effective {@link Hierarchy} of components. */
887:            public Hierarchy getHierarchy() {
888:                Resolver r = getResolver();
889:                if (r != null && r != this )
890:                    return r.getHierarchy();
891:                return hierarchy != null ? hierarchy : AWTHierarchy
892:                        .getDefault();
893:            }
894:
895:            /** Return a meaningful description of where the Step came from. */
896:            public String getContext(Step step) {
897:                return getFile().toString() + ":" + getLine(this , step);
898:            }
899:
900:            /** Return the file which defines the given step. */
901:            public static File getFile(Step step) {
902:                String context = step.getResolver().getContext(step);
903:                int colon = context.indexOf(":");
904:                if (colon == 1 && Character.isLetter(context.charAt(0))
905:                        && Platform.isWindows() && context.length() > 2)
906:                    colon = context.indexOf(":", 2);
907:                if (colon != -1)
908:                    context = context.substring(0, colon);
909:                return new File(context);
910:            }
911:
912:            /** Return the approximate line number of the given step.  File lines are
913:                one-based (there is no line zero).
914:             */
915:            public static int getLine(Step step) {
916:                String context = step.getResolver().getContext(step);
917:                int colon = context.indexOf(":");
918:                if (colon == 1 && Character.isLetter(context.charAt(0))
919:                        && Platform.isWindows() && context.length() > 2)
920:                    colon = context.indexOf(":", 2);
921:                context = context.substring(colon + 1);
922:                try {
923:                    return Integer.parseInt(context);
924:                } catch (NumberFormatException e) {
925:                    return -1;
926:                }
927:            }
928:
929:            private static int getLine(Sequence seq, Step step) {
930:                int line = -1;
931:                int index = seq.indexOf(step);
932:                if (index == -1) {
933:                    List list = seq.steps();
934:                    for (int i = 0; i < list.size(); i++) {
935:                        Step sub = (Step) list.get(i);
936:                        if (sub instanceof  Sequence) {
937:                            int subline = getLine((Sequence) sub, step);
938:                            if (subline != -1) {
939:                                line = countLines(seq, i) + subline;
940:                                break;
941:                            }
942:                        }
943:                    }
944:                } else {
945:                    line = countLines(seq, index);
946:                }
947:                return line;
948:            }
949:
950:            /** Return the number of XML lines in the given sequence that precede the
951:             * given index.  If the index is -1, return the number of XML lines used
952:             * by the whole sequence. 
953:             */
954:            public static int countLines(Sequence seq, int index) {
955:                int count = 1;
956:                int limit = index;
957:                if (limit == -1) {
958:                    limit = seq.size();
959:                    // Empty sequences take a single line
960:                    if (limit == 0)
961:                        return 1;
962:                    // Otherwise, 2 + the line count of the contents
963:                    count = 2;
964:                }
965:                if (seq instanceof  Script) {
966:                    // Add in one line per component reference in the script
967:                    // Plus two lines for the <xml> and <AWTTestScript> lines
968:                    count += ((Script) seq).getComponentReferences().size() + 2;
969:                }
970:                for (int i = 0; i < limit; i++) {
971:                    Step step = seq.getStep(i);
972:                    // Included scripts take only one line
973:                    if (step instanceof  Script) {
974:                        ++count;
975:                    } else if (step instanceof  Sequence) {
976:                        count += countLines((Sequence) step, -1);
977:                    } else {
978:                        ++count;
979:                    }
980:                }
981:                return count;
982:            }
983:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.