001    // Copyright 2004, 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.junit.mock;
016    
017    import ognl.Ognl;
018    import ognl.OgnlException;
019    import ognl.OgnlRuntime;
020    import org.apache.hivemind.ApplicationRuntimeException;
021    import org.apache.hivemind.HiveMind;
022    import org.apache.hivemind.Resource;
023    import org.apache.hivemind.util.PropertyUtils;
024    import org.apache.oro.text.regex.*;
025    import org.apache.tapestry.ApplicationServlet;
026    import org.apache.tapestry.test.mock.*;
027    import org.apache.tapestry.util.xml.DocumentParseException;
028    import org.jdom.Document;
029    import org.jdom.Element;
030    import org.jdom.input.SAXBuilder;
031    import org.testng.annotations.AfterClass;
032    import org.testng.annotations.AfterMethod;
033    import org.testng.annotations.DataProvider;
034    import org.testng.annotations.Test;
035    
036    import javax.servlet.ServletException;
037    import javax.servlet.http.Cookie;
038    import java.beans.Introspector;
039    import java.io.*;
040    import java.util.*;
041    
042    /**
043     * A complex class that reads an XML description of a test involving the Mock objects and executes
044     * it, pretending to be a running servlet container.
045     * <p>
046     * The XML format is pretty simple, it contains declarations similar to a web.xml deployment
047     * descriptor, a description of the active HttpSession (if any), a description of the HttpRequest,
048     * and then a set of expectations for the output stream from the request.
049     *
050     * @author Howard Lewis Ship
051     * @since 2.2
052     */
053    
054    public class TestMockApplications
055    {
056        public static final String LOGS_DIR = "target/logs";
057    
058        public static final String DEFAULT_BASE_DIR = "./";
059    
060        public static final String SCRIPTS_DIR = "src/scripts";
061    
062        private static String _baseDir;
063    
064        private String _testRootDirectory;
065    
066        private String _path;
067    
068        private String _fileName;
069    
070        private Document _document;
071    
072        private MockContext _context;
073    
074        private String _servletName;
075    
076        private ApplicationServlet _servlet;
077    
078        private MockRequest _request;
079    
080        private MockResponse _response;
081    
082        private int _requestNumber = 0;
083    
084        private Map _ognlContext = Ognl.createDefaultContext(this);
085    
086        private Throwable _exception;
087    
088        /**
089         * Shared cache of compiled patterns.
090         */
091    
092        private static Map _patternCache = new HashMap();
093    
094        private PatternMatcher _matcher = new Perl5Matcher();
095    
096        private PatternCompiler _compiler = new Perl5Compiler();
097    
098        private PrintStream _savedOut;
099    
100        private PrintStream _savedErr;
101    
102        private SAXBuilder _builder = new SAXBuilder();
103    
104        /**
105         * Closes System.out and System.err, then restores them to their original values.
106         */
107        @AfterMethod
108        public void tearDown() throws Exception
109        {
110            System.err.close();
111            System.setErr(_savedErr);
112    
113            System.out.close();
114            System.setOut(_savedOut);
115    
116            _requestNumber = 0;
117            _request = null;
118            _response = null;
119        }
120    
121        @DataProvider(name = "mockTestScripts")
122        public Object[][] createTestParameters()
123        {
124            List data = new ArrayList();
125    
126            File scriptsDir = new File(getBaseDirectory() + SCRIPTS_DIR);
127    
128            String[] names = scriptsDir.list();
129    
130            for (int i = 0; i < names.length; i++)
131            {
132                String name = names[i];
133    
134                if (name.endsWith(".xml"))
135                {
136                    data.add(new Object[] {
137                      getBaseDirectory() + "/src/test-data/",
138                      getBaseDirectory() + SCRIPTS_DIR + "/" + name,
139                      name
140                    });
141                }
142            }
143    
144            return (Object[][])data.toArray(new Object[data.size()][3]);
145        }
146    
147        public String toString()
148        {
149            StringBuffer buffer = new StringBuffer("MockTester[");
150    
151            if (_document != null)
152                buffer.append(_document);
153    
154            buffer.append(']');
155    
156            return buffer.toString();
157        }
158    
159        /**
160         * Invoked to execute the request cycle.
161         */
162        @Test(dataProvider = "mockTestScripts", enabled = false)
163        public void execute(String testRootDirectory, String path, String fileName)
164          throws Exception
165        {
166            _testRootDirectory = testRootDirectory;
167            _path = path;
168            _fileName = fileName;
169    
170            // setup and get environment ready
171            createLogs();
172            parse();
173            setup();
174    
175            Element root = _document.getRootElement();
176    
177            List l = root.getChildren("request");
178            int count = l.size();
179    
180            for (int i = 0; i < count; i++)
181            {
182                Element request = (Element) l.get(i);
183    
184                _requestNumber = i + 1;
185    
186                executeRequest(request);
187            }
188    
189            _servlet.destroy();
190    
191            PropertyUtils.clearCache();
192            OgnlRuntime.clearCache();
193            Introspector.flushCaches();
194        }
195    
196        private void executeRequest(Element request) throws IOException, DocumentParseException
197        {
198            Cookie[] oldRequestCookies = (_request == null ? null : _request.getCookies());
199    
200            _request = new MockRequest(_context, "/" + _servlet.getServletName());
201    
202            String contentType = request.getAttributeValue("content-type");
203            if (contentType != null)
204                _request.setContentType(contentType);
205    
206            String contentPath = request.getAttributeValue("content-path");
207            if (contentPath != null)
208                _request.setContentPath(_testRootDirectory + contentPath);
209    
210            _request.addCookies(oldRequestCookies);
211    
212            if (_response != null)
213                _request.addCookies(_response.getCookies());
214    
215            setupRequest(request);
216    
217            _exception = null;
218    
219            _response = new MockResponse(_request);
220    
221            try
222            {
223                _servlet.service(_request, _response);
224            }
225            catch (ServletException ex)
226            {
227                _exception = ex;
228            }
229            catch (IOException ex)
230            {
231                _exception = ex;
232            }
233    
234            _response.end();
235    
236            System.out.println("=== Response #" + _requestNumber + " ===\n\n");
237            System.out.println(_response.getOutputString());
238            System.out.println("\n\n");
239    
240            executeAssertions(request);
241        }
242    
243        private void parse()
244          throws Exception
245        {
246            _document = _builder.build(_path);
247        }
248    
249        private void setup() throws ServletException
250        {
251            Element root = _document.getRootElement();
252    
253            if (!root.getName().equals("mock-test"))
254                throw new RuntimeException("Root element of " + _path + " must be 'mock-test'.");
255    
256            System.setProperty("org.apache.tapestry.disable-caching", "false");
257    
258            setupContext(root);
259            setupServlet(root);
260        }
261    
262        private void setupContext(Element parent)
263        {
264            _context = new MockContext(_testRootDirectory);
265    
266            Element context = parent.getChild("context");
267    
268            if (context == null)
269                return;
270    
271            String name = context.getAttributeValue("name");
272    
273            if (name != null)
274                _context.setServletContextName(name);
275    
276            String root = context.getAttributeValue("root");
277    
278            if (root != null)
279                _context.setRootDirectory(_testRootDirectory + root);
280    
281            setInitParameters(context, _context);
282        }
283    
284        private void setupServlet(Element parent) throws ServletException
285        {
286            Element servlet = parent.getChild("servlet");
287    
288            String className = servlet.getAttributeValue("class");
289            _servletName = servlet.getAttributeValue("name");
290    
291            _servlet = createServlet(className);
292    
293            MockServletConfig config = new MockServletConfig(_servletName, _context);
294    
295            setInitParameters(servlet, config);
296    
297            _servlet.init(config);
298        }
299    
300        private void setupRequest(Element request)
301        {
302            String method = request.getAttributeValue("method");
303            if (method != null)
304                _request.setMethod(method);
305    
306            // It's really just the language from the locale.
307    
308            String locale = request.getAttributeValue("locale");
309            if (locale != null)
310                _request.setLocale(new Locale(locale, "", ""));
311    
312            List parameters = request.getChildren("parameter");
313            int count = parameters.size();
314    
315            for (int i = 0; i < count; i++)
316            {
317                Element parameter = (Element) parameters.get(i);
318    
319                setRequestParameter(parameter);
320            }
321    
322            String failover = request.getAttributeValue("failover");
323    
324            if (failover != null && failover.equals("true"))
325                _request.simulateFailover();
326    
327            // TBD: Headers, etc., etc.
328        }
329    
330        private void setRequestParameter(Element parameter)
331        {
332            List values = new ArrayList();
333    
334            String name = parameter.getAttributeValue("name");
335    
336            String value = parameter.getAttributeValue("value");
337            if (value != null)
338                values.add(value);
339    
340            List children = parameter.getChildren("value");
341            int count = children.size();
342            for (int i = 0; i < count; i++)
343            {
344                Element e = (Element) children.get(i);
345                value = e.getTextTrim();
346    
347                values.add(value);
348            }
349    
350            String[] array = (String[]) values.toArray(new String[values.size()]);
351    
352            _request.setParameter(name, array);
353        }
354    
355        private void setInitParameters(Element parent, InitParameterHolder holder)
356        {
357            List children = parent.getChildren("init-parameter");
358    
359            int count = children.size();
360            for (int i = 0; i < count; i++)
361            {
362                Element e = (Element) children.get(i);
363    
364                String name = e.getAttributeValue("name");
365                String value = e.getAttributeValue("value");
366    
367                holder.setInitParameter(name, value);
368            }
369        }
370    
371        private ApplicationServlet createServlet(String className)
372        {
373            Throwable t = null;
374            try
375            {
376                Class servletClass = Class.forName(className);
377    
378                return (ApplicationServlet) servletClass.newInstance();
379            }
380            catch (ClassNotFoundException ex)
381            {
382                t = ex;
383            }
384            catch (InstantiationException ex)
385            {
386                t = ex;
387            }
388            catch (IllegalAccessException ex)
389            {
390                t = ex;
391            }
392    
393            // Just a convient wrapper to percolate to the top and
394            // mark this test as an error.
395    
396            throw new ApplicationRuntimeException("Unable to instantiate servlet class " + className
397                                                  + ".", t);
398        }
399    
400        public MockContext getContext()
401        {
402            return _context;
403        }
404    
405        public MockRequest getRequest()
406        {
407            return _request;
408        }
409    
410        public MockResponse getResponse()
411        {
412            return _response;
413        }
414    
415        public ApplicationServlet getServlet()
416        {
417            return _servlet;
418        }
419    
420        private void executeAssertions(Element request) throws DocumentParseException
421        {
422            executeOutputAssertions(request);
423            executeNoOutputAssertions(request);
424            executeRegexpAssertions(request);
425            executeExpressionAssertions(request);
426            executeOutputMatchesAssertions(request);
427            executeCookieAssertions(request);
428            executeOutputStreamAssertions(request);
429            executeExceptionAssertions(request);
430        }
431    
432        /**
433         * Handles &lt;assert&gt; elements inside &lt;request&gt;. Each assertion is in the form of a
434         * boolean expression which must be true.
435         */
436    
437        private void executeExpressionAssertions(Element request) throws DocumentParseException
438        {
439            List l = request.getChildren("assert");
440            int count = l.size();
441    
442            for (int i = 0; i < count; i++)
443            {
444                Element a = (Element) l.get(i);
445    
446                String name = a.getAttributeValue("name");
447                String expression = a.getTextTrim();
448    
449                checkExpression(name, expression);
450            }
451        }
452    
453        private void checkExpression(String name, String expression) throws DocumentParseException
454        {
455    
456            boolean result = evaluate(expression);
457    
458            if (result)
459                return;
460    
461            throw new AssertionError(buildTestName(name) + ": Expression '" + expression
462                                     + "' was not true.");
463    
464        }
465    
466        private boolean evaluate(String expression) throws DocumentParseException
467        {
468            Object value = null;
469    
470            try
471            {
472                value = Ognl.getValue(expression, _ognlContext, this);
473            }
474            catch (OgnlException ex)
475            {
476                throw new DocumentParseException("Expression '" + expression + "' is not valid.", ex);
477            }
478    
479            if (value == null)
480                return false;
481    
482            if (value instanceof Boolean)
483                return ((Boolean) value).booleanValue();
484    
485            if (value instanceof Number)
486                return ((Number) value).longValue() != 0;
487    
488            if (value instanceof String)
489                return ((String) value).length() > 0;
490    
491            throw new DocumentParseException("Expression '" + expression + "' evaluates to ("
492                                             + value.getClass().getName() + ") " + value
493                                             + ", which cannot be interpreted as a boolean.");
494        }
495    
496        /**
497         * Handles &lt;assert-regexp&gt; elements inside &lt;request&gt;. Checks that a regular
498         * expression appears in the output. Content of element is the regular expression.
499         * <p>
500         * Attribute name is used in error messages.
501         */
502    
503        private void executeRegexpAssertions(Element request)
504          throws DocumentParseException
505        {
506            String outputString = null;
507    
508            List assertions = request.getChildren("assert-regexp");
509            int count = assertions.size();
510    
511            for (int i = 0; i < count; i++)
512            {
513                Element a = (Element) assertions.get(i);
514    
515                String name = a.getAttributeValue("name");
516                String pattern = a.getTextTrim();
517    
518                if (HiveMind.isBlank(pattern))
519                    throw new DocumentParseException("Pattern is null in " + a);
520    
521                if (outputString == null)
522                    outputString = _response.getOutputString();
523    
524                matchRegexp(name, outputString, pattern);
525            }
526    
527        }
528    
529        /**
530         * Handles &lt;assert-output&gt; elements inside &lt;request&gt;. Checks that a substring
531         * appears in the output. Content of element is the substring to search for.
532         * <p>
533         * Attribute name is used in error messages.
534         */
535    
536        private void executeOutputAssertions(Element request)
537          throws DocumentParseException
538        {
539            String outputString = null;
540    
541            List assertions = request.getChildren("assert-output");
542            int count = assertions.size();
543    
544            for (int i = 0; i < count; i++)
545            {
546                Element a = (Element) assertions.get(i);
547    
548                String name = a.getAttributeValue("name");
549                String substring = a.getTextTrim();
550    
551                if (HiveMind.isBlank(substring))
552                    throw new DocumentParseException("Substring is null in " + a);
553    
554                if (outputString == null)
555                    outputString = _response.getOutputString();
556    
557                matchSubstring(name, outputString, substring);
558            }
559    
560        }
561    
562        /**
563         * Handles &lt;assert-no-output&gt; elements inside &lt;request&gt;. Checks that a substring
564         * does not appear in the output. Content of element is the substring to search for.
565         * <p>
566         * Attribute name is used in error messages.
567         */
568    
569        private void executeNoOutputAssertions(Element request)
570          throws DocumentParseException
571        {
572            String outputString = null;
573    
574            List assertions = request.getChildren("assert-no-output");
575            int count = assertions.size();
576    
577            for (int i = 0; i < count; i++)
578            {
579                Element a = (Element) assertions.get(i);
580    
581                String name = a.getAttributeValue("name");
582                String substring = a.getTextTrim();
583    
584                if (HiveMind.isBlank(substring))
585                    throw new DocumentParseException("Substring is null in " + a, (Resource) null);
586    
587                if (outputString == null)
588                    outputString = _response.getOutputString();
589    
590                matchNoSubstring(name, outputString, substring);
591            }
592    
593        }
594    
595        private PatternMatcher getMatcher()
596        {
597            return _matcher;
598        }
599    
600        private Pattern compile(String pattern)
601          throws DocumentParseException
602        {
603            Pattern result = (Pattern) _patternCache.get(pattern);
604    
605            if (result != null)
606                return result;
607    
608            try
609            {
610                result = _compiler.compile(pattern, Perl5Compiler.MULTILINE_MASK);
611    
612            }
613            catch (MalformedPatternException ex)
614            {
615                throw new ApplicationRuntimeException("Malformed regular expression: " + pattern
616                                                      + " in " + _path + ".", ex);
617            }
618    
619            _patternCache.put(pattern, result);
620    
621            return result;
622        }
623    
624        private void matchRegexp(String name, String text, String pattern)
625          throws DocumentParseException
626        {
627            Pattern compiled = compile(pattern);
628    
629            if (getMatcher().contains(text, compiled))
630                return;
631    
632            System.err.println(text);
633    
634            throw new AssertionError(buildTestName(name)
635                                     + ": Response does not contain regular expression '" + pattern + "'.");
636        }
637    
638        private void matchSubstring(String name, String text, String substring)
639        {
640            if (text == null)
641                throw new AssertionError(buildTestName(name) + " : Response is null.");
642    
643            if (text.indexOf(substring) >= 0)
644                return;
645    
646            System.err.println(text);
647    
648            throw new AssertionError(buildTestName(name) + ":" + text + "\n Response does not contain string '"
649                                     + substring + "'.");
650        }
651    
652        private void matchNoSubstring(String name, String text, String substring)
653        {
654            if (text == null)
655                throw new AssertionError(buildTestName(name) + " : Response is null.");
656    
657            if (text.indexOf(substring) < 0)
658                return;
659    
660            System.err.println(text);
661    
662            throw new AssertionError(buildTestName(name) + ": Response contains string '"
663                                     + substring + "'.");
664        }
665    
666        private void executeOutputMatchesAssertions(Element request) throws DocumentParseException
667        {
668            List l = request.getChildren("assert-output-matches");
669            int count = l.size();
670            String outputString = null;
671    
672            for (int i = 0; i < count; i++)
673            {
674                Element e = (Element) l.get(i);
675    
676                if (outputString == null)
677                    outputString = _response.getOutputString();
678    
679                executeOutputMatchAssertion(e, outputString);
680            }
681    
682        }
683    
684        private void executeOutputMatchAssertion(Element element, String outputString)
685          throws DocumentParseException
686        {
687            String name = element.getAttributeValue("name");
688            String value = element.getAttributeValue("subgroup");
689            int subgroup = (value == null) ? 0 : Integer.parseInt(value);
690    
691            String pattern = element.getTextTrim();
692    
693            if (HiveMind.isBlank(pattern))
694                throw new DocumentParseException("Pattern is null in " + element);
695    
696            PatternMatcherInput input = new PatternMatcherInput(outputString);
697    
698            PatternMatcher matcher = getMatcher();
699            Pattern compiled = compile(pattern);
700    
701            List<Element> l = element.getChildren("match");
702            int count = l.size();
703            int i = 0;
704    
705            while (matcher.contains(input, compiled))
706            {
707                MatchResult match = matcher.getMatch();
708                String actual = match.group(subgroup);
709    
710                boolean matched = contentContains(l, actual);
711    
712                if (i >= count)
713                {
714                    System.err.println(outputString);
715                    throw new AssertionError(buildTestName(name) + ": Too many matches for '"
716                                             + pattern + "'.");
717                }
718    
719                if (!matched) {
720                    System.err.println(outputString);
721                    throw new AssertionError(buildTestName(name) + ": No expected match found for "
722                                             + "output of '" + actual + "'. ");
723                }
724    
725                i++;
726            }
727    
728            if (i < count)
729            {
730                System.err.println(outputString);
731                throw new AssertionError(buildTestName(name) + ": Too few matches for '"
732                                         + pattern + "' (expected " + count + " but got " + i + ").");
733            }
734        }
735    
736        private boolean contentContains(List<Element> elements, String text)
737        {
738            for (Element e : elements) {
739                if (e.getTextTrim().equals(text))
740                    return true;
741            }
742    
743            return false;
744        }
745    
746        private void executeExceptionAssertions(Element request)
747        {
748            List l = request.getChildren("assert-exception");
749            int count = l.size();
750    
751            for (int i = 0; i < count; i++)
752            {
753                Element assertion = (Element) l.get(i);
754    
755                executeExceptionAssertion(assertion);
756            }
757    
758        }
759    
760        private void executeExceptionAssertion(Element assertion)
761        {
762            String name = assertion.getAttributeValue("name");
763            String value = assertion.getTextTrim();
764    
765            if (_exception == null)
766                throw new AssertionError(buildTestName(name) + " no exception thrown.");
767            String message = _exception.getMessage();
768    
769            if (message.indexOf(value) >= 0)
770                return;
771    
772            throw new AssertionError(buildTestName(name) + " exception message (" + message
773                                     + ") does not contain '" + value + "'.");
774        }
775    
776        private void executeCookieAssertions(Element request)
777        {
778            List l = request.getChildren("assert-cookie");
779            int count = l.size();
780    
781            for (int i = 0; i < count; i++)
782            {
783                Element assertion = (Element) l.get(i);
784    
785                executeCookieAssertion(assertion);
786            }
787        }
788    
789        private void executeCookieAssertion(Element assertion)
790        {
791            String name = assertion.getAttributeValue("name");
792            String value = assertion.getAttributeValue("value");
793    
794            Cookie[] cookies = _response.getCookies();
795    
796            for (int i = 0; i < cookies.length; i++)
797            {
798                if (!cookies[i].getName().equals(name))
799                    continue;
800    
801                if (cookies[i].getValue().equals(value))
802                    return;
803    
804                throw new AssertionError(buildTestName(name) + ": Response cookie '" + name
805                                         + "': expected '" + value + "', but was '" + cookies[i].getValue() + "'.");
806            }
807    
808            throw new AssertionError(buildTestName(name) + ": Could not find cookie named '"
809                                     + name + "' in response.");
810        }
811    
812        private String buildTestName(String name)
813        {
814            return "Request #" + _requestNumber + "/" + name;
815        }
816    
817        private void executeOutputStreamAssertions(Element request) throws DocumentParseException
818        {
819            List l = request.getChildren("assert-output-stream");
820            int count = l.size();
821    
822            for (int i = 0; i < count; i++)
823            {
824                Element assertion = (Element) l.get(i);
825    
826                executeOutputStreamAssertion(assertion);
827            }
828    
829        }
830    
831        private void executeOutputStreamAssertion(Element element) throws DocumentParseException
832        {
833            String name = element.getAttributeValue("name");
834            String contentType = element.getAttributeValue("content-type");
835            String path = element.getAttributeValue("path");
836    
837            String actualContentType = _response.getContentType();
838    
839            if (!contentType.equals(actualContentType))
840                throw new AssertionError(buildTestName(name) + " content-type was '"
841                                         + actualContentType + "', expected '" + contentType + "'.");
842    
843            byte[] actualContent = _response.getResponseBytes();
844            byte[] expectedContent = getFileContent(getBaseDirectory() + "/" + path);
845    
846            if (actualContent.length != expectedContent.length)
847                throw new AssertionError(buildTestName(name) + " actual length of "
848                                         + actualContent.length + " bytes does not match expected length of "
849                                         + expectedContent.length + " bytes.");
850    
851            for (int i = 0; i < actualContent.length; i++)
852            {
853                if (actualContent[i] != expectedContent[i])
854                    throw new AssertionError(buildTestName(name)
855                                             + " content mismatch at index + " + i + ".");
856    
857            }
858        }
859    
860        private byte[] getFileContent(String path)
861        {
862            try
863            {
864                InputStream in = new FileInputStream(path);
865                ByteArrayOutputStream out = new ByteArrayOutputStream();
866    
867                byte[] buffer = new byte[1000];
868    
869                while (true)
870                {
871                    int length = in.read(buffer);
872                    if (length < 0)
873                        break;
874    
875                    out.write(buffer, 0, length);
876                }
877    
878                in.close();
879                out.close();
880    
881                return out.toByteArray();
882            }
883            catch (FileNotFoundException ex)
884            {
885                throw new ApplicationRuntimeException("File '" + path + "' not found.", ex);
886            }
887            catch (IOException ex)
888            {
889                throw new ApplicationRuntimeException("Unable to read file '" + path + "'.", ex);
890            }
891        }
892    
893        private void createLogs()
894          throws Exception
895        {
896            File outDir = new File(getBaseDirectory() + LOGS_DIR);
897    
898            if (!outDir.isDirectory())
899                outDir.mkdirs();
900    
901            _savedOut = System.out;
902            _savedErr = System.err;
903    
904            System.setOut(createPrintStream(outDir.getPath() + "/" + _fileName, "out"));
905            System.setErr(createPrintStream(outDir.getPath() + "/" + _fileName, "err"));
906        }
907    
908        private PrintStream createPrintStream(String path, String extension) throws Exception
909        {
910            File file = new File(path + "." + extension);
911    
912            // Open and truncate file.
913    
914            FileOutputStream fos = new FileOutputStream(file);
915    
916            BufferedOutputStream bos = new BufferedOutputStream(fos);
917    
918            return new PrintStream(bos, true);
919        }
920    
921        @AfterClass
922        public static void deleteDir()
923        {
924            File file = new File(getBaseDirectory() + "/target/.private");
925    
926            if (!file.exists())
927                return;
928    
929            deleteRecursive(file);
930        }
931    
932        private static void deleteRecursive(File file)
933        {
934            if (file.isFile())
935            {
936                file.delete();
937                return;
938            }
939    
940            String[] names = file.list();
941    
942            for (int i = 0; i < names.length; i++)
943            {
944                File f = new File(file, names[i]);
945                deleteRecursive(f);
946            }
947    
948            file.delete();
949        }
950    
951        public static String getBaseDirectory()
952        {
953            if (_baseDir == null) {
954                _baseDir = System.getProperty("BASEDIR", DEFAULT_BASE_DIR);
955                File test = new File(_baseDir + SCRIPTS_DIR);
956                if (!test.exists()) {
957                    test = new File(_baseDir + "tapestry-framework/" + SCRIPTS_DIR);
958                    if (test.exists())
959                        _baseDir = _baseDir + "tapestry-framework/";
960                }
961            }
962    
963            return _baseDir;
964        }
965    }