Source Code Cross Referenced for ScenarioRunner.java in  » UML » MetaBoss » com » metaboss » sdlctools » applications » systemtester » 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 » UML » MetaBoss » com.metaboss.sdlctools.applications.systemtester 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        // THIS SOFTWARE IS PROVIDED BY SOFTARIS PTY.LTD. AND OTHER METABOSS
0002:        // CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
0003:        // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
0004:        // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTARIS PTY.LTD.
0005:        // OR OTHER METABOSS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
0006:        // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0007:        // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
0008:        // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0009:        // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0010:        // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
0011:        // EVEN IF SOFTARIS PTY.LTD. OR OTHER METABOSS CONTRIBUTORS ARE ADVISED OF THE
0012:        // POSSIBILITY OF SUCH DAMAGE.
0013:        //
0014:        // Copyright 2000-2005 © Softaris Pty.Ltd. All Rights Reserved.
0015:        package com.metaboss.sdlctools.applications.systemtester;
0016:
0017:        import java.io.File;
0018:        import java.io.FileFilter;
0019:        import java.io.FileOutputStream;
0020:        import java.io.FileReader;
0021:        import java.io.IOException;
0022:        import java.io.PrintWriter;
0023:        import java.io.StringReader;
0024:        import java.io.StringWriter;
0025:        import java.lang.reflect.InvocationHandler;
0026:        import java.lang.reflect.InvocationTargetException;
0027:        import java.lang.reflect.Method;
0028:        import java.lang.reflect.Proxy;
0029:        import java.net.URL;
0030:        import java.net.URLClassLoader;
0031:        import java.text.SimpleDateFormat;
0032:        import java.util.ArrayList;
0033:        import java.util.Arrays;
0034:        import java.util.Calendar;
0035:        import java.util.Comparator;
0036:        import java.util.Date;
0037:        import java.util.HashMap;
0038:        import java.util.HashSet;
0039:        import java.util.Iterator;
0040:        import java.util.List;
0041:        import java.util.Map;
0042:        import java.util.Set;
0043:        import java.util.StringTokenizer;
0044:
0045:        import javax.xml.parsers.DocumentBuilder;
0046:        import javax.xml.parsers.DocumentBuilderFactory;
0047:        import javax.xml.transform.OutputKeys;
0048:        import javax.xml.transform.Transformer;
0049:        import javax.xml.transform.TransformerConfigurationException;
0050:        import javax.xml.transform.TransformerFactory;
0051:        import javax.xml.transform.dom.DOMSource;
0052:        import javax.xml.transform.stream.StreamResult;
0053:        import javax.xml.transform.stream.StreamSource;
0054:
0055:        import org.apache.commons.logging.Log;
0056:        import org.apache.commons.logging.LogFactory;
0057:        import org.jaxen.XPath;
0058:        import org.jaxen.dom.DOMXPath;
0059:        import org.w3c.dom.Attr;
0060:        import org.w3c.dom.Comment;
0061:        import org.w3c.dom.Document;
0062:        import org.w3c.dom.Element;
0063:        import org.w3c.dom.NamedNodeMap;
0064:        import org.w3c.dom.Node;
0065:        import org.w3c.dom.NodeList;
0066:        import org.xml.sax.ErrorHandler;
0067:        import org.xml.sax.InputSource;
0068:        import org.xml.sax.SAXException;
0069:        import org.xml.sax.SAXParseException;
0070:
0071:        import com.metaboss.util.DOMUtils;
0072:        import com.metaboss.util.DirectoryUtils;
0073:        import com.metaboss.util.ReflectionUtils;
0074:        import com.metaboss.util.StringUtils;
0075:
0076:        /** This class runs a single test scenario (note that scenarion may in fact consist of many test steps.
0077:         *  It should be called from command line and needs following arguments
0078:         *  <UL>
0079:         *  <LI>-scenarioPath=&lt;test scenario directory path&gt;. If it is not specified - the current working directory is used.
0080:         *  All xml files residing in this directory (apart from possible specimen xml file described below) will be read, sorted in alphabetical order
0081:         *  and executed in sequence.</LI>
0082:         *  <LI>-scenarioName=&lt;a name of this scenario&gt;. If it is not specified - "UnnamedScenario" name is used.
0083:         *  This is the name which is used to form a core of the log file name and also for the console output.
0084:         *  For example scenarioName might be 'MyRegressionTest' or 'AcceptanceScenarios' etc. The actual log file
0085:         *  name is formed by concatenating scenarioName, scenarioRunName and timestamp.</LI>
0086:         *  <LI>-scenarioRunName=&lt;a name of the run of this scenario&gt;. If it is not specified the empty string is used.
0087:         *  This is the name which is used to form a suffix of the log file name and also for the console output.
0088:         *  For example scenarioRunName might be 'JBossClient' or 'OracleInprocess' etc. The actual log file
0089:         *  name is formed by concatenating scenarioName, scenarioRunName and timestamp.</LI>
0090:         *  <LI>-clientPath=&lt;system clients configuration directory path&gt;. This directory should contain subdirectories with
0091:         *  names &lt;EnterpriseName&gt;.&lt;SystemName&gt;.&lt;ServicemoduleName&gt;. When runner parses scenarios it uses
0092:         *  namespace information from the test input documents to understand which client is needed, loads
0093:         *  contents of the matching directory in the specified path and executes servicemodule's xmlstrings adapter.
0094:         *  This basically allows for each client to be configurred and versioned separately (i.e. it may have different
0095:         *  versions of libraries etc...) If path is not given, path from under current directory is assumed. If 
0096:         *  directory is not found - attempt is made to load adapter from the system classpath</LI>
0097:         *  <LI>-loggingPath=&lt;test logs directory path&gt;. While runner is running - it outputs the log file (one per run).
0098:         *  The name of this file is formed from the scenarioName (see argument description above) and
0099:         *  date and time of the test. This ensures recognisable name of the log file and uniqueness of the names
0100:         *  even if same test is run more than once in quick succession.</LI>
0101:         *  <LI>-specimenFile=&lt;path and name of the scenario log specimen file&gt;. This parameter
0102:         *  triggers the test scenario validation against specified specimen file. This validation takes place
0103:         *  at the end of the scenario run. The specimen file is simply a previous good log file (i.e. result of good scenario run)
0104:         *  with all volotile data removed from it. Comparison process will ensure that all data in specimen file
0105:         *  is present in the log file being validated, <u>but not visa versa</u>. If this file is not specified
0106:         *  validation of the test data against the specimen is not performed.</LI>
0107:         *  <LI>-logTestPerformance=&lt;true or flse&gt;. Default is true. 
0108:         *  This argument controls output of the performance statistics records into the scenario log. Note that
0109:         *  by its nature performance data is volotile and there is usually a lot of it in the log. Therefore 
0110:         *  the presence of the performance data in the log makes it a bad candidate for a specimen. 
0111:         *  Unless you want to do lots of manual editing (i.e. deleting of performance data from the log file)
0112:         *  it is a good idea to switch off performance records output when capturing the log to be used as a specimen.</LI>
0113:         *  </UL>
0114:         */
0115:        public class ScenarioRunner {
0116:            private class SpecialFileFilter implements  FileFilter {
0117:                private Set mExcludeFilesPaths = new HashSet();
0118:
0119:                public SpecialFileFilter(File[] pExcludeFiles) {
0120:                    if (pExcludeFiles != null) {
0121:                        for (int i = 0; i < pExcludeFiles.length; i++) {
0122:                            mExcludeFilesPaths.add(pExcludeFiles[i]
0123:                                    .getAbsolutePath());
0124:                        }
0125:                    }
0126:                }
0127:
0128:                // Filter out not xml files and possible excluded files
0129:                public boolean accept(File pPathname) {
0130:                    return pPathname.isFile() == true
0131:                            && pPathname.isHidden() == false
0132:                            && pPathname.canRead() == true
0133:                            && pPathname.getName().toLowerCase().endsWith(
0134:                                    ".xml") == true
0135:                            && mExcludeFilesPaths.contains(pPathname
0136:                                    .getAbsolutePath()) == false;
0137:                }
0138:            };
0139:
0140:            private static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
0141:            private static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
0142:            private static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
0143:            private static final String W3C_XSLT_SCHEMA = "http://www.w3.org/1999/XSL/Transform";
0144:            private static final String METABOSS_SCENARIO_RUNNER_SCHEMA = "http://www.metaboss.com/XMLSchemas/MetaBoss/SdlcTools/SystemTester/1.0";
0145:            private static final String W3C_XMLNS_SCHEMA = "http://www.w3.org/2000/xmlns/";
0146:
0147:            private static final Log sLogger = LogFactory
0148:                    .getLog(ScenarioRunner.class);
0149:            private static final SimpleDateFormat sLogPathSuffixFormatter = new SimpleDateFormat(
0150:                    "yyyy-MM-dd HH.mm.ss");
0151:            private static final SimpleDateFormat sPerformanceDataTimestampFormatter = new SimpleDateFormat(
0152:                    "yyyy-MM-dd HH:mm:ss.SSS");
0153:            private static ScenarioRunner sScenarioRunnerInstance = null;
0154:            private String[] mIncludePath = null;
0155:            private String[] mScenarioPath = null;
0156:            private String mScenarioName = null;
0157:            private String mScenarioRunName = null;
0158:            private String mClientPath = null;
0159:            private String mLoggingPath = null;
0160:            private String mSpecimenFilePath = null;
0161:            private File mScenarioLogFile = null;
0162:            private boolean mScenarioLogNeedsSaving = false;
0163:            private TemplateContext mScenarioContext = null;
0164:            private boolean mLogTestPerformance = true;
0165:            private DocumentBuilder mScenarioDocumentBuilder = null;
0166:            private DocumentBuilder mAnyDocumentBuilder = null;
0167:            private DocumentBuilder mTransformationResultDocumentBuilder = null;
0168:            private TransformerFactory mTransformerFactory = null;
0169:            private Transformer mTestLogDocumentTransformer = null;
0170:
0171:            // Scenario variables. Get refreshed on every scenario run
0172:            private String mScenarioLoggingPath;
0173:            private String mScenarioClientPathPrefix;
0174:            private String mScenarioRootClassLoaderDirectoryPath;
0175:            private Date mTestLogStartTime;
0176:            private Map mAdapterRunners = new HashMap(); // Adapters indexed by namespace
0177:
0178:            // This class holds the current running context for the template invocation
0179:            // Template will be invoked with one of the elments referred by this class depending on scope 
0180:            private class TemplateContext {
0181:                public Document mTestLogDocument = null;
0182:                public Element mTestScenarioLogElement = null;
0183:                public Element mTopMostTestCaseLogElement = null; // The very first top level test case (used to insert comments before) 
0184:                public Element mTestCaseLogElement = null; // Current test case 
0185:                public List mTestCaseLogElementStack = new ArrayList(); // Stack of the previous ones, excluding the current
0186:                public Set mUsedIds = new HashSet();
0187:            }
0188:
0189:            public ScenarioRunner() throws Exception {
0190:                // Simple error handler - just outputs everything onto the log
0191:                ErrorHandler lErrorHandler = new ErrorHandler() {
0192:                    public void error(SAXParseException pException)
0193:                            throws SAXException {
0194:                        sLogger.error("XML Parser had error", pException);
0195:                        throw new SAXException(
0196:                                "Handler has intercepted parsing error.",
0197:                                pException);
0198:                    }
0199:
0200:                    public void fatalError(SAXParseException pException)
0201:                            throws SAXException {
0202:                        sLogger.fatal("XML Parser had fatal error", pException);
0203:                        throw new SAXException(
0204:                                "Handler has intercepted fatal parsing error.",
0205:                                pException);
0206:                    }
0207:
0208:                    public void warning(SAXParseException pException) {
0209:                        sLogger.warn("XML Parser had warning", pException);
0210:                    }
0211:                };
0212:                // Create simple validating document builder, which will read test documents.
0213:                {
0214:                    DocumentBuilderFactory dbf = DocumentBuilderFactory
0215:                            .newInstance();
0216:                    dbf.setNamespaceAware(true);
0217:                    dbf.setValidating(true);
0218:                    dbf.setIgnoringElementContentWhitespace(true);
0219:                    dbf.setIgnoringComments(true);
0220:                    dbf.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
0221:                    dbf.setAttribute(JAXP_SCHEMA_SOURCE, ScenarioRunner.class
0222:                            .getResourceAsStream("SystemTesterSchema.xsd"));
0223:                    mScenarioDocumentBuilder = dbf.newDocumentBuilder();
0224:                    mScenarioDocumentBuilder.setErrorHandler(lErrorHandler);
0225:                }
0226:                // Create simple validating any document builder, which will be used on inputs / outputs (any namespace)
0227:                {
0228:                    DocumentBuilderFactory dbf = DocumentBuilderFactory
0229:                            .newInstance();
0230:                    dbf.setNamespaceAware(true);
0231:                    dbf.setValidating(false);
0232:                    dbf.setIgnoringElementContentWhitespace(true);
0233:                    dbf.setIgnoringComments(true);
0234:                    mAnyDocumentBuilder = dbf.newDocumentBuilder();
0235:                    mAnyDocumentBuilder.setErrorHandler(lErrorHandler);
0236:                }
0237:                // Create transformation result document builder - dissolves CDATA
0238:                {
0239:                    DocumentBuilderFactory dbf = DocumentBuilderFactory
0240:                            .newInstance();
0241:                    dbf.setCoalescing(true);
0242:                    dbf.setNamespaceAware(true);
0243:                    dbf.setValidating(false);
0244:                    dbf.setIgnoringElementContentWhitespace(true);
0245:                    dbf.setIgnoringComments(true);
0246:                    mTransformationResultDocumentBuilder = dbf
0247:                            .newDocumentBuilder();
0248:                    mTransformationResultDocumentBuilder
0249:                            .setErrorHandler(lErrorHandler);
0250:                }
0251:
0252:                // Also create transformer factory 
0253:                mTransformerFactory = TransformerFactory.newInstance();
0254:            }
0255:
0256:            public synchronized void setScenarioPath(String pScenarioPath) {
0257:                mScenarioPath = pScenarioPath.split(";");
0258:            }
0259:
0260:            public synchronized void setIncludePath(String pIncludePath) {
0261:                mIncludePath = pIncludePath.split(";");
0262:            }
0263:
0264:            public synchronized void setScenarioName(String pScenarioName) {
0265:                mScenarioName = pScenarioName;
0266:            }
0267:
0268:            public synchronized void setScenarioRunName(String pScenarioRunName) {
0269:                mScenarioRunName = pScenarioRunName;
0270:            }
0271:
0272:            public synchronized void setClientPath(String pClientPath) {
0273:                mClientPath = new File(pClientPath).getAbsolutePath();
0274:            }
0275:
0276:            public synchronized void setLoggingPath(String pLoggingPath) {
0277:                mLoggingPath = new File(pLoggingPath).getAbsolutePath();
0278:            }
0279:
0280:            public synchronized void setSpecimenFile(String pSpecimenFile) {
0281:                mSpecimenFilePath = new File(pSpecimenFile).getAbsolutePath();
0282:            }
0283:
0284:            public synchronized void setLogTestPerformance(boolean pNeedToLog) {
0285:                mLogTestPerformance = pNeedToLog;
0286:            }
0287:
0288:            // This helper class is responsible for processing subscription events
0289:            private class SubscriptionHandler implements  InvocationHandler {
0290:                private Object mSubscriberInstance;
0291:                private TemplateContext mTemplateContext;
0292:                private Element mTargetSubscriptionLogElement;
0293:
0294:                // Constructor
0295:                public SubscriptionHandler(Class pSubscriberInterface,
0296:                        TemplateContext pTemplateContext,
0297:                        Element pTargetSubscriptionLogElement)
0298:                        throws TransformerConfigurationException {
0299:                    mTemplateContext = pTemplateContext;
0300:                    mTargetSubscriptionLogElement = pTargetSubscriptionLogElement;
0301:                    mSubscriberInstance = Proxy.newProxyInstance(
0302:                            pSubscriberInterface.getClassLoader(),
0303:                            new Class[] { pSubscriberInterface }, this );
0304:                }
0305:
0306:                // Getter for the subscriber instance
0307:                public Object getSubscriberInstance() {
0308:                    return mSubscriberInstance;
0309:                }
0310:
0311:                // Handle any subscriber method
0312:                public Object invoke(Object proxy, Method method, Object[] args)
0313:                        throws Throwable {
0314:                    String lMethodName = method.getName();
0315:                    sLogger.debug("Method " + lMethodName
0316:                            + " has been invoked on event subscriber object");
0317:                    Date lInvocationTime = new Date();
0318:                    // Filter special methods
0319:                    if (lMethodName.equals("onEvent") && args != null
0320:                            && args.length == 1) {
0321:                        String lEventDocumentString = (String) args[0];
0322:                        Document lEventDocument = mAnyDocumentBuilder
0323:                                .parse(new InputSource(new StringReader(
0324:                                        lEventDocumentString)));
0325:                        Element lEventElement = lEventDocument
0326:                                .getDocumentElement();
0327:                        Element lEventLogElement = (Element) mTargetSubscriptionLogElement
0328:                                .appendChild(mTemplateContext.mTestLogDocument
0329:                                        .createElement("SubscriptionEventLog"));
0330:                        // Append performance information if necessary
0331:                        if (mLogTestPerformance) {
0332:                            Element lArrivalElement = (Element) lEventLogElement
0333:                                    .appendChild(mTemplateContext.mTestLogDocument
0334:                                            .createElement("Arrival"));
0335:                            populateTimestampElement(lArrivalElement,
0336:                                    lInvocationTime);
0337:                        }
0338:                        lEventLogElement
0339:                                .appendChild(mTemplateContext.mTestLogDocument
0340:                                        .importNode(lEventElement, true));
0341:                        // Log the test output
0342:                        if (sLogger.isDebugEnabled()) {
0343:                            StringWriter lIndentedResultFileContents = new StringWriter();
0344:                            // Initialise transformer to use in this class
0345:                            Transformer lTransformer = mTransformerFactory
0346:                                    .newTransformer();
0347:                            lTransformer.setOutputProperty(OutputKeys.METHOD,
0348:                                    "xml");
0349:                            lTransformer.setOutputProperty(
0350:                                    OutputKeys.STANDALONE, "yes");
0351:                            lTransformer.setOutputProperty(OutputKeys.INDENT,
0352:                                    "yes");
0353:                            lTransformer.transform(
0354:                                    new DOMSource(lEventDocument),
0355:                                    new StreamResult(
0356:                                            lIndentedResultFileContents));
0357:                            sLogger.debug("Received following event:\r\n"
0358:                                    + lIndentedResultFileContents);
0359:                        }
0360:                    } else if (lMethodName.equals("subscriptionInitiated")
0361:                            && args != null && args.length == 1) {
0362:                        String lEventDocumentString = (String) args[0];
0363:                        Document lEventDocument = mAnyDocumentBuilder
0364:                                .parse(new InputSource(new StringReader(
0365:                                        lEventDocumentString)));
0366:                        Element lEventElement = lEventDocument
0367:                                .getDocumentElement();
0368:                        Element lEventLogElement = (Element) mTargetSubscriptionLogElement
0369:                                .appendChild(mTemplateContext.mTestLogDocument
0370:                                        .createElement("SubscriptionInitiatedLog"));
0371:                        // Append performance information if necessary
0372:                        if (mLogTestPerformance) {
0373:                            Element lArrivalElement = (Element) lEventLogElement
0374:                                    .appendChild(mTemplateContext.mTestLogDocument
0375:                                            .createElement("Arrival"));
0376:                            populateTimestampElement(lArrivalElement,
0377:                                    lInvocationTime);
0378:                        }
0379:                        lEventLogElement
0380:                                .appendChild(mTemplateContext.mTestLogDocument
0381:                                        .importNode(lEventElement, true));
0382:                        // Log the test output
0383:                        if (sLogger.isDebugEnabled()) {
0384:                            StringWriter lIndentedResultFileContents = new StringWriter();
0385:                            // Initialise transformer to use in this class
0386:                            Transformer lTransformer = mTransformerFactory
0387:                                    .newTransformer();
0388:                            lTransformer.setOutputProperty(OutputKeys.METHOD,
0389:                                    "xml");
0390:                            lTransformer.setOutputProperty(
0391:                                    OutputKeys.STANDALONE, "yes");
0392:                            lTransformer.setOutputProperty(OutputKeys.INDENT,
0393:                                    "yes");
0394:                            lTransformer.transform(
0395:                                    new DOMSource(lEventDocument),
0396:                                    new StreamResult(
0397:                                            lIndentedResultFileContents));
0398:                            sLogger
0399:                                    .debug("Received 'subscriptionInitiated' event with following data:\r\n"
0400:                                            + lIndentedResultFileContents);
0401:                        }
0402:                    } else if (lMethodName.equals("subscriptionInterrupted")
0403:                            && args != null && args.length == 1) {
0404:                        Element lEventLogElement = (Element) mTargetSubscriptionLogElement
0405:                                .appendChild(mTemplateContext.mTestLogDocument
0406:                                        .createElement("SubscriptionInterruptedLog"));
0407:                        // Append performance information if necessary
0408:                        if (mLogTestPerformance) {
0409:                            Element lArrivalElement = (Element) lEventLogElement
0410:                                    .appendChild(mTemplateContext.mTestLogDocument
0411:                                            .createElement("Arrival"));
0412:                            populateTimestampElement(lArrivalElement,
0413:                                    lInvocationTime);
0414:                        }
0415:                        if (args[0] != null) {
0416:                            appendExceptionElement(lEventLogElement,
0417:                                    (Throwable) args[0]);
0418:                            if (sLogger.isDebugEnabled())
0419:                                sLogger
0420:                                        .debug(
0421:                                                "Received 'subscriptionInterrupted' event with causing exception information.\r\n",
0422:                                                (Throwable) args[0]);
0423:                        } else {
0424:                            if (sLogger.isDebugEnabled())
0425:                                sLogger
0426:                                        .debug("Received 'subscriptionInterrupted' event without exception information.");
0427:                        }
0428:                    } else if (lMethodName.equals("subscriptionRestored")
0429:                            && (args == null || args.length == 0)) {
0430:                        Element lEventLogElement = (Element) mTargetSubscriptionLogElement
0431:                                .appendChild(mTemplateContext.mTestLogDocument
0432:                                        .createElement("SubscriptionRestoredLog"));
0433:                        // Append performance information if necessary
0434:                        if (mLogTestPerformance) {
0435:                            Element lArrivalElement = (Element) lEventLogElement
0436:                                    .appendChild(mTemplateContext.mTestLogDocument
0437:                                            .createElement("Arrival"));
0438:                            populateTimestampElement(lArrivalElement,
0439:                                    lInvocationTime);
0440:                        }
0441:                        if (sLogger.isDebugEnabled())
0442:                            sLogger
0443:                                    .debug("Received 'subscriptionRestored' event.");
0444:                    } else if (lMethodName.equals("subscriptionTerminated")
0445:                            && (args == null || args.length == 0)) {
0446:                        Element lEventLogElement = (Element) mTargetSubscriptionLogElement
0447:                                .appendChild(mTemplateContext.mTestLogDocument
0448:                                        .createElement("SubscriptionTerminatedLog"));
0449:                        // Append performance information if necessary
0450:                        if (mLogTestPerformance) {
0451:                            Element lArrivalElement = (Element) lEventLogElement
0452:                                    .appendChild(mTemplateContext.mTestLogDocument
0453:                                            .createElement("Arrival"));
0454:                            populateTimestampElement(lArrivalElement,
0455:                                    lInvocationTime);
0456:                        }
0457:                        if (sLogger.isDebugEnabled())
0458:                            sLogger
0459:                                    .debug("Received 'subscriptionTerminated' event.");
0460:                    } else
0461:                    // Filter some basic java.lang.Object methods
0462:                    if (lMethodName.equals("hashCode")
0463:                            && (args == null || args.length == 0))
0464:                        return new Integer(hashCode());
0465:                    else if (lMethodName.equals("toString")
0466:                            && (args == null || args.length == 0))
0467:                        return new String(toString());
0468:                    else if (lMethodName.equals("equals") && args != null
0469:                            && args.length == 1)
0470:                        return new Boolean(equals(args[0]));
0471:                    return null;
0472:                }
0473:            }
0474:
0475:            // This helper class caches the instance of the underlying service adapter and provides 
0476:            // ability to execute services or subscribe for events 
0477:            private class AdapterRunner {
0478:                private ClassLoader mContextClassloader;
0479:                private Object mAdapterInstance;
0480:                private Method mExecuteMethod;
0481:                private Class mSubscriberInterface;
0482:                private Method mSubscribeMethod;
0483:                private Method mUnsubscribeMethod;
0484:
0485:                // Creates the adapter runner for the namespace 		
0486:                public AdapterRunner(String pNamespace) throws IOException,
0487:                        ClassNotFoundException, NoSuchMethodException,
0488:                        InstantiationException, IllegalAccessException {
0489:                    // Disassemble the namespace. Load class and obtain reflect method
0490:                    StringTokenizer lTokenizer = new StringTokenizer(
0491:                            pNamespace, "/", false);
0492:                    if (lTokenizer.countTokens() != 5)
0493:                        throw new IllegalArgumentException(
0494:                                "Namespace '"
0495:                                        + pNamespace
0496:                                        + "' is not valid. Expected format <EnterpriseName>/Systems/<SystemName>/Services/<ServicemoduleName>");
0497:                    String lEnterpriseName = lTokenizer.nextToken();
0498:                    if (!lTokenizer.nextToken().equals("Systems"))
0499:                        throw new IllegalArgumentException(
0500:                                "Namespace '"
0501:                                        + pNamespace
0502:                                        + "' is not valid. Expected format <EnterpriseName>/Systems/<SystemName>/Services/<ServicemoduleName>");
0503:                    String lSystemName = lTokenizer.nextToken();
0504:                    if (!lTokenizer.nextToken().equals("Services"))
0505:                        throw new IllegalArgumentException(
0506:                                "Namespace '"
0507:                                        + pNamespace
0508:                                        + "' is not valid. Expected format <EnterpriseName>/Systems/<SystemName>/Services/<ServicemoduleName>");
0509:                    String lServicemoduleName = lTokenizer.nextToken();
0510:                    String lAdapterClassName = "com."
0511:                            + lEnterpriseName.toLowerCase() + "."
0512:                            + lSystemName.toLowerCase()
0513:                            + ".adapters.generic.xmlstrings.services."
0514:                            + lServicemoduleName.toLowerCase()
0515:                            + ".ADServicemodule";
0516:                    List lURLs = new ArrayList();
0517:                    File lAdapterDirectory = new File(mScenarioClientPathPrefix
0518:                            + lEnterpriseName + "." + lSystemName + "."
0519:                            + lServicemoduleName).getAbsoluteFile();
0520:                    if (lAdapterDirectory.exists()) {
0521:                        lURLs.add(lAdapterDirectory.toURL());
0522:                        // Add jars
0523:                        File[] lFiles = lAdapterDirectory
0524:                                .listFiles(new FileFilter() {
0525:                                    public boolean accept(File pPathname) {
0526:                                        return pPathname.isFile()
0527:                                                && pPathname.getName()
0528:                                                        .toLowerCase()
0529:                                                        .endsWith(".jar");
0530:                                    }
0531:                                });
0532:                        // Load all files one by one	
0533:                        for (int i = 0; i < lFiles.length; i++)
0534:                            lURLs.add(lFiles[i].toURL());
0535:                    }
0536:                    lURLs.add(new File(mScenarioRootClassLoaderDirectoryPath)
0537:                            .toURL());
0538:                    mContextClassloader = new URLClassLoader((URL[]) lURLs
0539:                            .toArray(new URL[lURLs.size()]));
0540:
0541:                    // Instantiate adapter class
0542:                    Class lAdapterClass = mContextClassloader
0543:                            .loadClass(lAdapterClassName);
0544:                    mAdapterInstance = lAdapterClass.newInstance();
0545:
0546:                    // Find the method used to execute operations
0547:                    mExecuteMethod = lAdapterClass.getMethod(
0548:                            "executeOperation", new Class[] { String.class });
0549:
0550:                    // Find subscriber interface
0551:                    mSubscriberInterface = ReflectionUtils.getInnerClass(
0552:                            lAdapterClass, "Subscriber");
0553:                    mSubscribeMethod = lAdapterClass.getMethod("subscribe",
0554:                            new Class[] { mSubscriberInterface, String.class });
0555:                    mUnsubscribeMethod = lAdapterClass.getMethod("unsubscribe",
0556:                            new Class[] { mSubscriberInterface });
0557:                }
0558:
0559:                public String executeOperation(String pInputDocument)
0560:                        throws InvocationTargetException,
0561:                        IllegalAccessException {
0562:                    Thread lExecutionThread = Thread.currentThread();
0563:                    ClassLoader lOriginalContextClassloader = lExecutionThread
0564:                            .getContextClassLoader();
0565:                    try {
0566:                        lExecutionThread
0567:                                .setContextClassLoader(mContextClassloader);
0568:                        return (String) mExecuteMethod.invoke(mAdapterInstance,
0569:                                new Object[] { pInputDocument });
0570:                    } finally {
0571:                        lExecutionThread
0572:                                .setContextClassLoader(lOriginalContextClassloader);
0573:                    }
0574:                }
0575:
0576:                public String subscribe(String pInputDocument,
0577:                        TemplateContext pTemplateContext,
0578:                        Element pTargetSubscriptionLogElement)
0579:                        throws InvocationTargetException,
0580:                        IllegalAccessException,
0581:                        TransformerConfigurationException {
0582:                    // Create subscriber which implements required interface
0583:                    SubscriptionHandler lHandler = new SubscriptionHandler(
0584:                            mSubscriberInterface, pTemplateContext,
0585:                            pTargetSubscriptionLogElement);
0586:                    Thread lExecutionThread = Thread.currentThread();
0587:                    ClassLoader lOriginalContextClassloader = lExecutionThread
0588:                            .getContextClassLoader();
0589:                    try {
0590:                        lExecutionThread
0591:                                .setContextClassLoader(mContextClassloader);
0592:                        return (String) mSubscribeMethod.invoke(
0593:                                mAdapterInstance, new Object[] {
0594:                                        lHandler.getSubscriberInstance(),
0595:                                        pInputDocument });
0596:                    } finally {
0597:                        lExecutionThread
0598:                                .setContextClassLoader(lOriginalContextClassloader);
0599:                    }
0600:                }
0601:            }
0602:
0603:            /** Runs scenario and returns true if test was successfull and false otherwise */
0604:            public synchronized boolean runScenario() throws Exception {
0605:                // If scenario name is not given - use Unnamed
0606:                if (mScenarioName == null || mScenarioName.length() == 0)
0607:                    mScenarioName = "UnnamedScenario";
0608:                // Do a bit of a trick to get absolute path to even cwd
0609:                mScenarioClientPathPrefix = (mClientPath != null && mClientPath
0610:                        .length() > 0) ? (mClientPath + File.separator) : "";
0611:                // Initialise default classloader - will load all jars fom the path trick below just to cater for the case if we are using curr working dir
0612:                mScenarioRootClassLoaderDirectoryPath = new File(
0613:                        mScenarioClientPathPrefix + "jnk.txt")
0614:                        .getAbsoluteFile().getParent();
0615:
0616:                mAdapterRunners.clear();
0617:                // We will make sure that directory exists, but will not clean it up
0618:                String lScenarioRunName = mScenarioName
0619:                        + ((mScenarioRunName != null) ? ("_" + mScenarioRunName)
0620:                                : "");
0621:                mScenarioLogFile = new File(
0622:                        ((mLoggingPath != null && mLoggingPath.length() > 0) ? (mLoggingPath + File.separator)
0623:                                : "")
0624:                                + lScenarioRunName
0625:                                + "_"
0626:                                + sLogPathSuffixFormatter.format(new Date())
0627:                                + ".xml");
0628:                DirectoryUtils.ensureThereIsDirectory(mScenarioLogFile
0629:                        .getAbsoluteFile().getParent());
0630:
0631:                // Obtain all xml files in all directoris on scenario path (may be excluding some files, such as specimen for example)
0632:                File[] lExcludedFiles = mSpecimenFilePath != null ? (new File[] { new File(
0633:                        mSpecimenFilePath) })
0634:                        : new File[0];
0635:                // Special case - if scenario path is not given than the scenario is in the current directory
0636:                if (mScenarioPath == null || mScenarioPath.length == 0)
0637:                    mScenarioPath = new String[] { new File("jnk.txt")
0638:                            .getAbsoluteFile().getParentFile()
0639:                            .getAbsolutePath() };
0640:                ArrayList lTestInputFilesList = new ArrayList();
0641:                for (int i = 0; i < mScenarioPath.length; i++) {
0642:                    File lScenarioDirectory = new File(mScenarioPath[i])
0643:                            .getAbsoluteFile();
0644:                    sLogger.info("Scanning " + lScenarioDirectory
0645:                            + " directory for the test cases to execute.");
0646:                    File[] lTestInputFiles = lScenarioDirectory
0647:                            .listFiles(new SpecialFileFilter(lExcludedFiles));
0648:                    if (lTestInputFiles == null || lTestInputFiles.length == 0) {
0649:                        sLogger.info("Found no test cases to execute in "
0650:                                + lScenarioDirectory + " directory");
0651:                        continue;
0652:                    }
0653:                    sLogger.info("Found "
0654:                            + Integer.toString(lTestInputFiles.length)
0655:                            + " test cases to execute in " + lScenarioDirectory
0656:                            + " directory");
0657:                    // Sort files by name and than add to the common list
0658:                    // This way files will be sorted within the directory 			
0659:                    Arrays.sort(lTestInputFiles, new Comparator() {
0660:                        public int compare(Object o1, Object o2) {
0661:                            return ((File) o1).getName().compareTo(
0662:                                    ((File) o2).getName());
0663:                        }
0664:                    });
0665:                    lTestInputFilesList.addAll(Arrays.asList(lTestInputFiles));
0666:                }
0667:                if (lTestInputFilesList.size() == 0) {
0668:                    sLogger.info("Found no test cases to execute.");
0669:                    return false;
0670:                }
0671:                sLogger.info("Commenced scenario " + lScenarioRunName);
0672:                sLogger.info("Scenario log will be saved in "
0673:                        + mScenarioLogFile.getAbsolutePath() + " file.");
0674:                if (lTestInputFilesList.size() == 1)
0675:                    sLogger.info("Found one test case to execute.");
0676:                else
0677:                    sLogger.info("Found " + lTestInputFilesList.size()
0678:                            + " test cases to execute.");
0679:
0680:                // Initialise  test log start time close to the beginnig of tests
0681:                mTestLogStartTime = new Date();
0682:
0683:                mTestLogDocumentTransformer = mTransformerFactory
0684:                        .newTransformer();
0685:                mTestLogDocumentTransformer.setOutputProperty(
0686:                        OutputKeys.METHOD, "xml");
0687:                mTestLogDocumentTransformer.setOutputProperty(
0688:                        OutputKeys.STANDALONE, "yes");
0689:                mTestLogDocumentTransformer.setOutputProperty(
0690:                        OutputKeys.INDENT, "yes");
0691:
0692:                mScenarioContext = new TemplateContext();
0693:                mScenarioContext.mTestLogDocument = mScenarioDocumentBuilder
0694:                        .newDocument();
0695:                // For a start - create scenario element in default namsepace
0696:                // Once document is fully built - we will move it into the namespace before saving
0697:                mScenarioContext.mTestScenarioLogElement = (Element) mScenarioContext.mTestLogDocument
0698:                        .appendChild(mScenarioContext.mTestLogDocument
0699:                                .createElement("TestScenarioLog"));
0700:                mScenarioContext.mTestScenarioLogElement.setAttribute("name",
0701:                        mScenarioName);
0702:                mScenarioContext.mTestScenarioLogElement.setAttribute("status",
0703:                        "InProgress");
0704:                boolean lHadTestCasesFailure = false; // Register failures so the final outcome can be established and reported
0705:                // From now on we should attempt to save the scenario log regardless of the way in which application has been terminated
0706:                mScenarioLogNeedsSaving = true;
0707:                try {
0708:                    try {
0709:                        try {
0710:                            // Save file at the beginning for debugging purposes
0711:
0712:                            // Keep last formed TestStepLogElement for possible transformation
0713:                            for (int i = 0; i < lTestInputFilesList.size(); i++) {
0714:                                File lTestCaseDocumentFile = (File) lTestInputFilesList
0715:                                        .get(i);
0716:                                sLogger
0717:                                        .info("  Commenced test case defined in "
0718:                                                + lTestCaseDocumentFile
0719:                                                        .getAbsolutePath());
0720:                                // Load test definition into dom document
0721:                                Document lInputDocument = parseDocumentWithoutNamespace(new InputSource(
0722:                                        new FileReader(lTestCaseDocumentFile)));
0723:
0724:                                // Dump document it into debug string
0725:                                {
0726:                                    Transformer lTransformer = mTransformerFactory
0727:                                            .newTransformer();
0728:                                    lTransformer.setOutputProperty(
0729:                                            OutputKeys.METHOD, "xml");
0730:                                    lTransformer.setOutputProperty(
0731:                                            OutputKeys.STANDALONE, "yes");
0732:                                    lTransformer.setOutputProperty(
0733:                                            OutputKeys.INDENT, "no");
0734:                                    StringWriter lRawStringWriter = new StringWriter();
0735:                                    lTransformer.transform(new DOMSource(
0736:                                            lInputDocument), new StreamResult(
0737:                                            lRawStringWriter));
0738:                                    sLogger.debug("Test case definition:\r\n"
0739:                                            + lRawStringWriter.toString());
0740:                                }
0741:                                // Get the top element of the tree, ensure that this is a TestCasePlan element
0742:                                Element lTestCasePlanElement = lInputDocument
0743:                                        .getDocumentElement();
0744:                                if (!lTestCasePlanElement.getTagName().equals(
0745:                                        "TestCasePlan"))
0746:                                    throw new Exception(
0747:                                            "File "
0748:                                                    + lTestCaseDocumentFile
0749:                                                            .getAbsolutePath()
0750:                                                    + " must have TestCasePlan element as its root element");
0751:                                // See if we need to set the name up
0752:                                if (!lTestCasePlanElement.hasAttribute("name")) {
0753:                                    // Get rid of .xml and set the file name as the name of the test
0754:                                    String lTestCaseName = lTestCaseDocumentFile
0755:                                            .getName()
0756:                                            .substring(
0757:                                                    0,
0758:                                                    lTestCaseDocumentFile
0759:                                                            .getName().length() - 4);
0760:                                    lTestCasePlanElement.setAttribute("name",
0761:                                            lTestCaseName);
0762:                                }
0763:                                Element lTestCaseLogElement = doTheTestCase(
0764:                                        lTestCasePlanElement, mScenarioContext);
0765:                                sLogger.info("  Completed "
0766:                                        + lTestCaseLogElement
0767:                                                .getAttribute("name")
0768:                                        + " test case defined in "
0769:                                        + lTestCaseDocumentFile
0770:                                                .getAbsolutePath()
0771:                                        + " Status: "
0772:                                        + lTestCaseLogElement
0773:                                                .getAttribute("status"));
0774:                                if (!lHadTestCasesFailure) {
0775:                                    String lTestCaseStatus = lTestCaseLogElement
0776:                                            .getAttribute("status");
0777:                                    if ((!lTestCaseStatus.equals("Success"))
0778:                                            && (!lTestCaseStatus
0779:                                                    .equals("PrerequisiteFailure")))
0780:                                        lHadTestCasesFailure = true;
0781:                                }
0782:                            }
0783:                            // If we have had test step failure - register it.
0784:                            if (lHadTestCasesFailure) {
0785:                                mScenarioContext.mTestScenarioLogElement
0786:                                        .setAttribute("status",
0787:                                                "ChildCaseFailure");
0788:                                Comment lComment = mScenarioContext.mTestLogDocument
0789:                                        .createComment("One or more of the child test cases have failed.");
0790:                                mScenarioContext.mTestScenarioLogElement
0791:                                        .insertBefore(
0792:                                                lComment,
0793:                                                mScenarioContext.mTopMostTestCaseLogElement);
0794:                            } else {
0795:                                mScenarioContext.mTestScenarioLogElement
0796:                                        .setAttribute("status", "Success");
0797:                                Comment lComment = mScenarioContext.mTestLogDocument
0798:                                        .createComment("All child test cases have succeeded.");
0799:                                mScenarioContext.mTestScenarioLogElement
0800:                                        .insertBefore(
0801:                                                lComment,
0802:                                                mScenarioContext.mTopMostTestCaseLogElement);
0803:                            }
0804:                        } finally {
0805:                            // Create performance record if necessary
0806:                            if (mLogTestPerformance)
0807:                                appendPerformanceElement(
0808:                                        mScenarioContext.mTestScenarioLogElement,
0809:                                        mTestLogStartTime, new Date());
0810:                        }
0811:                    } catch (Throwable t) {
0812:                        if (t instanceof  InvocationTargetException)
0813:                            t = ((InvocationTargetException) t)
0814:                                    .getTargetException();
0815:                        sLogger
0816:                                .debug("Test scenario has resulted in exception: "
0817:                                        + t.getMessage());
0818:                        appendExceptionElement(
0819:                                mScenarioContext.mTestScenarioLogElement, t);
0820:                        // By default if scenario has completed with exception - it is deemed to be a failure
0821:                        mScenarioContext.mTestScenarioLogElement.setAttribute(
0822:                                "status", "ExceptionFailure");
0823:                        Comment lComment = mScenarioContext.mTestLogDocument
0824:                                .createComment("Java exception occurred during test scenario execution.");
0825:                        mScenarioContext.mTestScenarioLogElement.insertBefore(
0826:                                lComment,
0827:                                mScenarioContext.mTopMostTestCaseLogElement);
0828:                        lHadTestCasesFailure = true; // Somethig wrong - indicate failure
0829:                    } finally {
0830:                        // Output the test cases completion message
0831:                        sLogger
0832:                                .info("Completed all test cases. Completion Status : "
0833:                                        + mScenarioContext.mTestScenarioLogElement
0834:                                                .getAttribute("status"));
0835:                        // Set namespace before saving the document. This will ensure that document is valid and readable
0836:                        // Setting namespace before than might have made templating more difficult
0837:                        mScenarioContext.mTestScenarioLogElement
0838:                                .setAttributeNS(W3C_XMLNS_SCHEMA, "xmlns",
0839:                                        METABOSS_SCENARIO_RUNNER_SCHEMA);
0840:
0841:                        // If there is a specimen file - we need to compare them and 
0842:                        // override the answer if cpecimen and this log are equal
0843:                        if (mSpecimenFilePath != null) {
0844:                            try {
0845:                                sLogger
0846:                                        .info("Commencing test scenario validation against specimen. Specimen file: "
0847:                                                + mSpecimenFilePath);
0848:                                File lSpecimenFile = new File(mSpecimenFilePath);
0849:                                // Load test definition into dom document
0850:                                Document lSpecimenDocument = parseDocumentWithoutNamespace(new InputSource(
0851:                                        new FileReader(lSpecimenFile)));
0852:                                Document lSampleDocument = mScenarioContext.mTestLogDocument;
0853:                                // Suppress failure if comparison against specimen is successfull
0854:                                String[] lErrorMessages = SpecimenComparator
0855:                                        .compareAgainstSpecimen(
0856:                                                lSpecimenDocument,
0857:                                                lSampleDocument, false, true);
0858:                                if (lErrorMessages != null) {
0859:                                    mScenarioContext.mTestScenarioLogElement
0860:                                            .setAttribute("status",
0861:                                                    "SpecimenMismatch");
0862:                                    Comment lComment = mScenarioContext.mTestLogDocument
0863:                                            .createComment("Test scenario validation has failed. Detected "
0864:                                                    + lErrorMessages.length
0865:                                                    + " mismatches with the specimen. Specimen file: "
0866:                                                    + mSpecimenFilePath
0867:                                                    + ". See the end of this file for mismatch details.");
0868:                                    mScenarioContext.mTestScenarioLogElement
0869:                                            .insertBefore(
0870:                                                    lComment,
0871:                                                    mScenarioContext.mTopMostTestCaseLogElement);
0872:                                    lHadTestCasesFailure = true;
0873:                                    // There are error messages - print them out and also add them as comments at the end of the log
0874:                                    for (int i = 0; i < lErrorMessages.length; i++) {
0875:                                        sLogger.info("  " + lErrorMessages[i]);
0876:                                        Comment lMismatchComment = mScenarioContext.mTestLogDocument
0877:                                                .createComment("Specimen mismatch: "
0878:                                                        + lErrorMessages[i]);
0879:                                        mScenarioContext.mTestScenarioLogElement
0880:                                                .appendChild(lMismatchComment);
0881:                                    }
0882:                                    sLogger
0883:                                            .info("Test scenario validation has failed. Detected "
0884:                                                    + lErrorMessages.length
0885:                                                    + " mismatches with the specimen.");
0886:                                } else {
0887:                                    sLogger
0888:                                            .info("Test scenario validation has succeeded. No mismatches with the specimen have been detected.");
0889:                                    // Supress failures because comparison with the specimen has been successfull					
0890:                                    mScenarioContext.mTestScenarioLogElement
0891:                                            .setAttribute("status", "Success");
0892:                                    Comment lComment = mScenarioContext.mTestLogDocument
0893:                                            .createComment("Test scenario validation has succeeded. No mismatches with the specimen have been detected. Specimen file: "
0894:                                                    + mSpecimenFilePath + ".");
0895:                                    mScenarioContext.mTestScenarioLogElement
0896:                                            .insertBefore(
0897:                                                    lComment,
0898:                                                    mScenarioContext.mTopMostTestCaseLogElement);
0899:                                    lHadTestCasesFailure = false;
0900:                                }
0901:                            } catch (Throwable t) {
0902:                                if (t instanceof  InvocationTargetException)
0903:                                    t = ((InvocationTargetException) t)
0904:                                            .getTargetException();
0905:                                sLogger
0906:                                        .debug("Test scenario validation has resulted in exception: "
0907:                                                + t.getMessage());
0908:                                appendExceptionElement(
0909:                                        mScenarioContext.mTestScenarioLogElement,
0910:                                        t);
0911:                                // By default if scenario has completed with exception - it is deemed to be a failure
0912:                                mScenarioContext.mTestScenarioLogElement
0913:                                        .setAttribute("status",
0914:                                                "ExceptionFailure");
0915:                                Comment lComment = mScenarioContext.mTestLogDocument
0916:                                        .createComment("Java exception occurred during validation of the test scenario against the specimen. Specimen file: "
0917:                                                + mSpecimenFilePath + ".");
0918:                                mScenarioContext.mTestScenarioLogElement
0919:                                        .insertBefore(
0920:                                                lComment,
0921:                                                mScenarioContext.mTopMostTestCaseLogElement);
0922:                                lHadTestCasesFailure = true; // Somethig wrong - indicate failure
0923:                            }
0924:                        } else {
0925:                            sLogger
0926:                                    .info("Specimen file is not specified. Test scenario validation against specimen is omitted.");
0927:                            Comment lComment = mScenarioContext.mTestLogDocument
0928:                                    .createComment("Specimen file was not specified. Test scenario validation against specimen was omitted.");
0929:                            mScenarioContext.mTestScenarioLogElement
0930:                                    .insertBefore(
0931:                                            lComment,
0932:                                            mScenarioContext.mTopMostTestCaseLogElement);
0933:                        }
0934:                    }
0935:                } finally {
0936:                    saveScenarioLogIfNecessary();
0937:                    // Log information about this scenario
0938:                    sLogger.info("Completed "
0939:                            + lScenarioRunName
0940:                            + " Test scenario run. Completion Status : "
0941:                            + mScenarioContext.mTestScenarioLogElement
0942:                                    .getAttribute("status"));
0943:                }
0944:                return !lHadTestCasesFailure; // Return actual result
0945:            }
0946:
0947:            // Save scenario file if necessary
0948:            public void saveScenarioLogIfNecessary() throws Exception {
0949:                if (mScenarioLogNeedsSaving == true) {
0950:                    synchronized (mScenarioLogFile) {
0951:                        if (mScenarioLogNeedsSaving == true) {
0952:                            mTestLogDocumentTransformer.transform(
0953:                                    new DOMSource(
0954:                                            mScenarioContext.mTestLogDocument),
0955:                                    new StreamResult(new FileOutputStream(
0956:                                            mScenarioLogFile)));
0957:                            sLogger.info("Test log is saved into the "
0958:                                    + mScenarioLogFile.getAbsolutePath());
0959:                            mScenarioLogNeedsSaving = false;
0960:                        }
0961:                    }
0962:                }
0963:            }
0964:
0965:            // Helper. Populates timestamp element with values. Deals with any Start, Stop, Arrival	
0966:            private void populateTimestampElement(Element pTimestampElement,
0967:                    Date pTimestamp) {
0968:                Document pOwnerDocument = pTimestampElement.getOwnerDocument();
0969:                Element lTimestampElement = (Element) pTimestampElement
0970:                        .appendChild(pOwnerDocument.createElement("Timestamp"));
0971:                lTimestampElement.appendChild(pOwnerDocument
0972:                        .createTextNode(sPerformanceDataTimestampFormatter
0973:                                .format(pTimestamp)));
0974:                Element lJavatimestampElement = (Element) pTimestampElement
0975:                        .appendChild(pOwnerDocument
0976:                                .createElement("JavaTimestamp"));
0977:                lJavatimestampElement.appendChild(pOwnerDocument
0978:                        .createTextNode(Long.toString(pTimestamp.getTime())));
0979:                Element lLogtimestampElement = (Element) pTimestampElement
0980:                        .appendChild(pOwnerDocument
0981:                                .createElement("LogTimestamp"));
0982:                lLogtimestampElement.appendChild(pOwnerDocument
0983:                        .createTextNode(Long.toString(pTimestamp.getTime()
0984:                                - mTestLogStartTime.getTime())));
0985:            }
0986:
0987:            // Helper. Appends performance element to the specified element	
0988:            private void appendPerformanceElement(Element pParentElement,
0989:                    Date pStartTimestamp, Date pEndTimestamp) {
0990:                Document pOwnerDocument = pParentElement.getOwnerDocument();
0991:                Element lPerformanceElement = (Element) pParentElement
0992:                        .appendChild(pOwnerDocument
0993:                                .createElement("PerformanceDocument"));
0994:                // Do start element
0995:                {
0996:                    Element lStartElement = (Element) lPerformanceElement
0997:                            .appendChild(pOwnerDocument.createElement("Start"));
0998:                    populateTimestampElement(lStartElement, pStartTimestamp);
0999:                }
1000:
1001:                // Do end element
1002:                {
1003:                    Element lEndElement = (Element) lPerformanceElement
1004:                            .appendChild(pOwnerDocument.createElement("End"));
1005:                    populateTimestampElement(lEndElement, pEndTimestamp);
1006:                }
1007:                // Do duration element
1008:                {
1009:                    Element lDurationElement = (Element) lPerformanceElement
1010:                            .appendChild(pOwnerDocument
1011:                                    .createElement("Duration"));
1012:                    lDurationElement.appendChild(pOwnerDocument
1013:                            .createTextNode(Long.toString(pEndTimestamp
1014:                                    .getTime()
1015:                                    - pStartTimestamp.getTime())));
1016:                }
1017:            }
1018:
1019:            // Helper. Appends information about exception element to the specified element	
1020:            private void appendExceptionElement(Element pTestStepLogElement,
1021:                    Throwable pException) {
1022:                Document lOwnerDocument = pTestStepLogElement
1023:                        .getOwnerDocument();
1024:                Element lExceptionElement = (Element) pTestStepLogElement
1025:                        .appendChild(lOwnerDocument
1026:                                .createElement("ExceptionDocument"));
1027:                // Do java class element
1028:                {
1029:                    Element lJavaClassElement = (Element) lExceptionElement
1030:                            .appendChild(lOwnerDocument
1031:                                    .createElement("JavaClassName"));
1032:                    lJavaClassElement.appendChild(lOwnerDocument
1033:                            .createTextNode(pException.getClass().getName()));
1034:                }
1035:
1036:                // Do message element (do CDATA ourselves)
1037:                {
1038:                    Element lMessageTextElement = (Element) lExceptionElement
1039:                            .appendChild(lOwnerDocument
1040:                                    .createElement("ExceptionMessage"));
1041:                    String lExceptionMessage = pException.getMessage();
1042:                    if (lExceptionMessage != null)
1043:                        lMessageTextElement.appendChild(lOwnerDocument
1044:                                .createTextNode(lExceptionMessage));
1045:                }
1046:
1047:                // Do string element
1048:                {
1049:                    Element lStringTextElement = (Element) lExceptionElement
1050:                            .appendChild(lOwnerDocument
1051:                                    .createElement("ExceptionString"));
1052:                    lStringTextElement.appendChild(lOwnerDocument
1053:                            .createTextNode(pException.toString()));
1054:                }
1055:                // Do stack element
1056:                {
1057:                    StringWriter lStringWriter = new StringWriter();
1058:                    pException.printStackTrace(new PrintWriter(lStringWriter));
1059:                    Element lStackTraceElement = (Element) lExceptionElement
1060:                            .appendChild(lOwnerDocument
1061:                                    .createElement("StackTrace"));
1062:                    lStackTraceElement.appendChild(lOwnerDocument
1063:                            .createTextNode(lStringWriter.toString()));
1064:                }
1065:            }
1066:
1067:            // Helper. Runs single test step and returns TestCaseLog element 
1068:            private Element doTheTestCase(Element pTestCasePlanElement,
1069:                    TemplateContext pTemplateContext) throws Exception {
1070:                // Ensure that test case has a name
1071:                if (!pTestCasePlanElement.hasAttribute("name"))
1072:                    pTestCasePlanElement
1073:                            .setAttribute("name", "UnnamedTestCase");
1074:                if (!pTestCasePlanElement.hasAttribute("numberOfRuns")) {
1075:                    return doTheTestCase_SingleRun(pTestCasePlanElement,
1076:                            pTemplateContext, null);
1077:                } else {
1078:                    String lLogIndent = StringUtils
1079:                            .getIndent(
1080:                                    2,
1081:                                    pTemplateContext.mTestCaseLogElementStack
1082:                                            .size()
1083:                                            + (pTemplateContext.mTestCaseLogElement != null ? 3
1084:                                                    : 2));
1085:                    Element lTestCaseLogElement = null;
1086:                    try {
1087:                        // Log information about this test case
1088:                        sLogger.info(lLogIndent + "Commenced "
1089:                                + pTestCasePlanElement.getAttribute("name")
1090:                                + " TestCase Series");
1091:
1092:                        int lNumberOfRuns = Integer
1093:                                .parseInt(pTestCasePlanElement
1094:                                        .getAttribute("numberOfRuns"));
1095:
1096:                        lTestCaseLogElement = pTemplateContext.mTestLogDocument
1097:                                .createElement("TestCaseLog");
1098:                        // Put the previous log on the stack and create our own log element 
1099:                        if (pTemplateContext.mTestCaseLogElement != null) {
1100:                            // This is a sub test case
1101:                            Element lParentTestCaseElement = pTemplateContext.mTestCaseLogElement;
1102:                            pTemplateContext.mTestCaseLogElementStack.add(0,
1103:                                    lParentTestCaseElement);
1104:                            pTemplateContext.mTestCaseLogElement = (Element) lParentTestCaseElement
1105:                                    .appendChild(lTestCaseLogElement);
1106:                        } else {
1107:                            pTemplateContext.mTestCaseLogElement = (Element) pTemplateContext.mTestScenarioLogElement
1108:                                    .appendChild(lTestCaseLogElement);
1109:                            // Remember if this is first every test case
1110:                            if (pTemplateContext.mTopMostTestCaseLogElement == null)
1111:                                pTemplateContext.mTopMostTestCaseLogElement = pTemplateContext.mTestCaseLogElement;
1112:                        }
1113:                        copyBaseElements(pTestCasePlanElement,
1114:                                pTemplateContext.mTestCaseLogElement,
1115:                                pTemplateContext);
1116:                        pTemplateContext.mTestCaseLogElement.setAttribute(
1117:                                "status", "InProgress");
1118:                        // Go in the loop through all runs and call this method recursively
1119:                        {
1120:                            boolean lHadChildTestCasesFailure = false;
1121:                            for (int lRunNumber = 1; lRunNumber <= lNumberOfRuns; lRunNumber++) {
1122:                                Element lChildTestCaseLogElement = doTheTestCase_SingleRun(
1123:                                        pTestCasePlanElement, pTemplateContext,
1124:                                        new Integer(lRunNumber));
1125:                                String lChldTestCaseStatus = lChildTestCaseLogElement
1126:                                        .getAttribute("status");
1127:                                // Update status to the child case failed if necessary
1128:                                if (!lHadChildTestCasesFailure) {
1129:                                    if ((!lChldTestCaseStatus.equals("Success"))
1130:                                            && (!lChldTestCaseStatus
1131:                                                    .equals("PrerequisiteFailure"))) {
1132:                                        lHadChildTestCasesFailure = true;
1133:                                        pTemplateContext.mTestCaseLogElement
1134:                                                .setAttribute("status",
1135:                                                        "ChildCaseFailure");
1136:                                    }
1137:                                }
1138:                                // Get out of runs if child case status is anything but success
1139:                                if (!lChldTestCaseStatus.equals("Success")) {
1140:                                    break;
1141:                                }
1142:                            }
1143:                        }
1144:                        // Set successful status if the test case survived so far without failure
1145:                        String lCurrentTestCaseStatus = pTemplateContext.mTestCaseLogElement
1146:                                .getAttribute("status");
1147:                        if (lCurrentTestCaseStatus.equals("InProgress"))
1148:                            pTemplateContext.mTestCaseLogElement.setAttribute(
1149:                                    "status", "Success");
1150:                        return pTemplateContext.mTestCaseLogElement;
1151:                    } finally {
1152:                        // Log information about this test case
1153:                        sLogger.info(lLogIndent
1154:                                + "Completed "
1155:                                + pTestCasePlanElement.getAttribute("name")
1156:                                + " TestCase Series. Status: "
1157:                                + pTemplateContext.mTestCaseLogElement
1158:                                        .getAttribute("status"));
1159:                        // Restore the previous element on a stack if the current element is ours
1160:                        if (lTestCaseLogElement != null
1161:                                && pTemplateContext.mTestCaseLogElement == lTestCaseLogElement) {
1162:                            if (pTemplateContext.mTestCaseLogElementStack
1163:                                    .size() > 0)
1164:                                pTemplateContext.mTestCaseLogElement = (Element) pTemplateContext.mTestCaseLogElementStack
1165:                                        .remove(0);
1166:                            else
1167:                                pTemplateContext.mTestCaseLogElement = null;
1168:                        }
1169:                    }
1170:                }
1171:            }
1172:
1173:            // Helper. Runs single test step and returns TestCaseLog element 
1174:            private Element doTheTestCase_SingleRun(
1175:                    Element pTestCasePlanElement,
1176:                    TemplateContext pTemplateContext, Integer pRunNumber)
1177:                    throws Exception {
1178:                // Obtain desired indent
1179:                String lLogIndent = StringUtils
1180:                        .getIndent(
1181:                                2,
1182:                                pTemplateContext.mTestCaseLogElementStack
1183:                                        .size()
1184:                                        + (pTemplateContext.mTestCaseLogElement != null ? 3
1185:                                                : 2));
1186:                Element lTestCaseLogElement = null;
1187:                try {
1188:                    // Log information about this test case
1189:                    sLogger.info(lLogIndent + "Commenced "
1190:                            + pTestCasePlanElement.getAttribute("name")
1191:                            + " TestCase");
1192:
1193:                    lTestCaseLogElement = pTemplateContext.mTestLogDocument
1194:                            .createElement("TestCaseLog");
1195:                    // Put the previous log on the stack and create our own log element 
1196:                    if (pTemplateContext.mTestCaseLogElement != null) {
1197:                        // This is a sub test case
1198:                        Element lParentTestCaseElement = pTemplateContext.mTestCaseLogElement;
1199:                        pTemplateContext.mTestCaseLogElementStack.add(0,
1200:                                lParentTestCaseElement);
1201:                        pTemplateContext.mTestCaseLogElement = (Element) lParentTestCaseElement
1202:                                .appendChild(lTestCaseLogElement);
1203:                    } else {
1204:                        pTemplateContext.mTestCaseLogElement = (Element) pTemplateContext.mTestScenarioLogElement
1205:                                .appendChild(lTestCaseLogElement);
1206:                        // Remember if this is first every test case
1207:                        if (pTemplateContext.mTopMostTestCaseLogElement == null)
1208:                            pTemplateContext.mTopMostTestCaseLogElement = pTemplateContext.mTestCaseLogElement;
1209:                    }
1210:                    copyBaseElements(pTestCasePlanElement,
1211:                            pTemplateContext.mTestCaseLogElement,
1212:                            pTemplateContext);
1213:                    if (pRunNumber != null)
1214:                        pTemplateContext.mTestCaseLogElement.setAttribute(
1215:                                "runNumber", pRunNumber.toString());
1216:                    pTemplateContext.mTestCaseLogElement.setAttribute("status",
1217:                            "InProgress");
1218:                    // First work on sleep before 
1219:                    if (pTestCasePlanElement.hasAttribute("sleepBefore")) {
1220:                        String lSecondsToSleep = pTestCasePlanElement
1221:                                .getAttribute("sleepBefore");
1222:                        if (sLogger.isDebugEnabled())
1223:                            sLogger
1224:                                    .info("Will sleep for "
1225:                                            + lSecondsToSleep
1226:                                            + " seconds as defined in the sleepBefore attribute of the TestCase...");
1227:                        Thread
1228:                                .sleep((long) (Integer
1229:                                        .parseInt(lSecondsToSleep) * 1000));
1230:                        pTemplateContext.mTestCaseLogElement.setAttribute(
1231:                                "sleepBefore", lSecondsToSleep);
1232:                    }
1233:                    Date lTestCaseStart = new Date();
1234:                    try {
1235:                        Element lTestCaseSubElement = DOMUtils
1236:                                .getFirstChildElement(pTestCasePlanElement);
1237:                        // See if this element is PrerequisiteDocument
1238:                        if (lTestCaseSubElement.getTagName().equals(
1239:                                "PrerequisiteDocument")) {
1240:                            Element lTargetPrerequisiteDocumentElement = (Element) pTemplateContext.mTestCaseLogElement
1241:                                    .appendChild(pTemplateContext.mTestLogDocument
1242:                                            .createElement("PrerequisiteDocument"));
1243:                            copyChildElementsWithoutNamespacesWithTemplates(
1244:                                    lTargetPrerequisiteDocumentElement,
1245:                                    lTestCaseSubElement, pTemplateContext);
1246:                            // Now - analyse prerequisite element and determine whether test step outcome has to be overturned
1247:                            // Presence of any ErrorMessages or AbstainMessages will indicate that test should not be run
1248:                            NodeList lErrorMessagesList = lTargetPrerequisiteDocumentElement
1249:                                    .getElementsByTagName("ErrorMessage");
1250:                            if (lErrorMessagesList.getLength() > 0) {
1251:                                // Prerequisite document contains some errors, no point to continue
1252:                                pTemplateContext.mTestCaseLogElement
1253:                                        .setAttribute("status",
1254:                                                "PrerequisiteFailure");
1255:                                return pTemplateContext.mTestCaseLogElement;
1256:                            }
1257:                            NodeList lAbstainMessagesList = lTargetPrerequisiteDocumentElement
1258:                                    .getElementsByTagName("AbstainMessage");
1259:                            if (lAbstainMessagesList.getLength() > 0) {
1260:                                // Prerequisite document contains some abstain reasons, no point to continue
1261:                                pTemplateContext.mTestCaseLogElement
1262:                                        .setAttribute("status",
1263:                                                "PrerequisiteFailure");
1264:                                return pTemplateContext.mTestCaseLogElement;
1265:                            }
1266:                            lTestCaseSubElement = DOMUtils
1267:                                    .getNextSiblingElement(lTestCaseSubElement);
1268:                        }
1269:                        // See if this element is a parameters document
1270:                        if (lTestCaseSubElement.getTagName().equals(
1271:                                "ParametersDocument")) {
1272:                            // Parameters document should just be copied into the log (with templates), which will make it available for other templates
1273:                            Element lTargetParametersDocumentElement = (Element) pTemplateContext.mTestCaseLogElement
1274:                                    .appendChild(pTemplateContext.mTestLogDocument
1275:                                            .createElement("ParametersDocument"));
1276:                            copyBaseElements(lTargetParametersDocumentElement,
1277:                                    lTestCaseSubElement, pTemplateContext);
1278:                            copyChildElementsWithoutNamespacesWithTemplates(
1279:                                    lTargetParametersDocumentElement,
1280:                                    lTestCaseSubElement, pTemplateContext);
1281:                            lTestCaseSubElement = DOMUtils
1282:                                    .getNextSiblingElement(lTestCaseSubElement);
1283:                        }
1284:                        // Go in the loop through all of child test plans, operation plans and templates and call this method recursively
1285:                        boolean lHadChildTestCasesFailure = false;
1286:                        boolean lHadSomethingToDo = false;
1287:                        for (; lTestCaseSubElement != null
1288:                                && (lTestCaseSubElement.getTagName().equals(
1289:                                        "TestCasePlan")
1290:                                        || lTestCaseSubElement.getTagName()
1291:                                                .equals("OperationPlan")
1292:                                        || lTestCaseSubElement.getTagName()
1293:                                                .equals("Template") || lTestCaseSubElement
1294:                                        .getTagName()
1295:                                        .equals("SubscriptionPlan")); lTestCaseSubElement = DOMUtils
1296:                                .getNextSiblingElement(lTestCaseSubElement)) {
1297:                            lHadSomethingToDo = true;
1298:                            // See if this element is OperationPlan
1299:                            if (lTestCaseSubElement.getTagName().equals(
1300:                                    "OperationPlan")) {
1301:                                // Process operation 
1302:                                processOperationPlan(
1303:                                        pTemplateContext.mTestCaseLogElement,
1304:                                        lTestCaseSubElement, pTemplateContext);
1305:                            } else
1306:                            // See if this element is SubscriptionPlan
1307:                            if (lTestCaseSubElement.getTagName().equals(
1308:                                    "SubscriptionPlan")) {
1309:                                // Process operation 
1310:                                processSubscriptionPlan(
1311:                                        pTemplateContext.mTestCaseLogElement,
1312:                                        lTestCaseSubElement, pTemplateContext);
1313:                            } else
1314:                            // See if we have a series of child test cases
1315:                            if (lTestCaseSubElement.getTagName().equals(
1316:                                    "TestCasePlan")) {
1317:                                Element lChildTestCaseLogElement = doTheTestCase(
1318:                                        lTestCaseSubElement, pTemplateContext);
1319:                                if (!lHadChildTestCasesFailure) {
1320:                                    String lChldTestCaseStatus = lChildTestCaseLogElement
1321:                                            .getAttribute("status");
1322:                                    if ((!lChldTestCaseStatus.equals("Success"))
1323:                                            && (!lChldTestCaseStatus
1324:                                                    .equals("PrerequisiteFailure"))) {
1325:                                        lHadChildTestCasesFailure = true;
1326:                                        pTemplateContext.mTestCaseLogElement
1327:                                                .setAttribute("status",
1328:                                                        "ChildCaseFailure");
1329:                                    }
1330:                                }
1331:                            } else
1332:                            // See if we have to process template (there could only be one of these)
1333:                            if (lTestCaseSubElement.getTagName().equals(
1334:                                    "Template")) {
1335:                                // Process template or template text. Default scope for the template is current test case
1336:                                Document lTempDocument = mScenarioDocumentBuilder
1337:                                        .newDocument();
1338:                                Element lTestSubElementsList = lTempDocument
1339:                                        .createElement("InternalTestStepList");
1340:                                processTemplate(lTestSubElementsList,
1341:                                        lTestCaseSubElement, pTemplateContext);
1342:                                // Analyse what have we got
1343:                                Element lGeneratedTestCaseSubElement = DOMUtils
1344:                                        .getFirstChildElement(lTestSubElementsList);
1345:                                if (lGeneratedTestCaseSubElement == null)
1346:                                    throw new Exception(
1347:                                            "No elements have been produced as the result of running a template. Expecting <TestCasePlan> or <OperationPlan>");
1348:                                // Go in the loop through all of child test plans and call this method recursively
1349:                                boolean lHadSomethingToDoAfterTemplate = false;
1350:                                for (; lGeneratedTestCaseSubElement != null
1351:                                        && (lGeneratedTestCaseSubElement
1352:                                                .getTagName().equals(
1353:                                                        "TestCasePlan") || lGeneratedTestCaseSubElement
1354:                                                .getTagName().equals(
1355:                                                        "OperationPlan")); lGeneratedTestCaseSubElement = DOMUtils
1356:                                        .getNextSiblingElement(lGeneratedTestCaseSubElement)) {
1357:                                    lHadSomethingToDoAfterTemplate = true;
1358:                                    // See if this element is OperationPlan
1359:                                    if (lGeneratedTestCaseSubElement
1360:                                            .getTagName().equals(
1361:                                                    "OperationPlan")) {
1362:                                        // Process operation 
1363:                                        processOperationPlan(
1364:                                                pTemplateContext.mTestCaseLogElement,
1365:                                                lGeneratedTestCaseSubElement,
1366:                                                pTemplateContext);
1367:                                    } else
1368:                                    // See if this element is SubscriptionPlan
1369:                                    if (lGeneratedTestCaseSubElement
1370:                                            .getTagName().equals(
1371:                                                    "SubscriptionPlan")) {
1372:                                        // Process operation 
1373:                                        processSubscriptionPlan(
1374:                                                pTemplateContext.mTestCaseLogElement,
1375:                                                lGeneratedTestCaseSubElement,
1376:                                                pTemplateContext);
1377:                                    } else
1378:                                    // See if we have a series of child test cases
1379:                                    if (lGeneratedTestCaseSubElement
1380:                                            .getTagName()
1381:                                            .equals("TestCasePlan")) {
1382:                                        Element lChildTestCaseLogElement = doTheTestCase(
1383:                                                lGeneratedTestCaseSubElement,
1384:                                                pTemplateContext);
1385:                                        if (!lHadChildTestCasesFailure) {
1386:                                            String lChldTestCaseStatus = lChildTestCaseLogElement
1387:                                                    .getAttribute("status");
1388:                                            if ((!lChldTestCaseStatus
1389:                                                    .equals("Success"))
1390:                                                    && (!lChldTestCaseStatus
1391:                                                            .equals("PrerequisiteFailure"))) {
1392:                                                lHadChildTestCasesFailure = true;
1393:                                                pTemplateContext.mTestCaseLogElement
1394:                                                        .setAttribute("status",
1395:                                                                "ChildCaseFailure");
1396:                                            }
1397:                                        }
1398:                                    }
1399:                                }
1400:                                if (lHadSomethingToDoAfterTemplate == false)
1401:                                    throw new Exception(
1402:                                            "Unexpected element type resulted from running a template. Expecting <TestCasePlan> or <OperationPlan>, got <"
1403:                                                    + lGeneratedTestCaseSubElement
1404:                                                            .getTagName() + ">");
1405:                            }
1406:                        }
1407:                        if (lHadSomethingToDo == false)
1408:                            throw new Exception(
1409:                                    "Unexpected element type. Expecting <TestCasePlan> or <OperationPlan> or <Template>, got <"
1410:                                            + lTestCaseSubElement.getTagName()
1411:                                            + ">");
1412:                        // Set successful status if the test case survived so far without failure
1413:                        String lCurrentTestCaseStatus = pTemplateContext.mTestCaseLogElement
1414:                                .getAttribute("status");
1415:                        if (lCurrentTestCaseStatus.equals("InProgress"))
1416:                            pTemplateContext.mTestCaseLogElement.setAttribute(
1417:                                    "status", "Success");
1418:                    } catch (Throwable t) {
1419:                        if (t instanceof  InvocationTargetException)
1420:                            t = ((InvocationTargetException) t)
1421:                                    .getTargetException();
1422:                        sLogger.debug("Test case has resulted in exception "
1423:                                + t.getClass().getName()
1424:                                + " Exception Message: " + t.getMessage());
1425:                        appendExceptionElement(
1426:                                pTemplateContext.mTestCaseLogElement, t);
1427:                        // By default if service has completed with exception - it is deemed to be a failure
1428:                        pTemplateContext.mTestCaseLogElement.setAttribute(
1429:                                "status", "ExceptionFailure");
1430:                    } finally {
1431:                        // See if there is an acceptance document, which may overrun the result
1432:                        Element lTestCaseSubElement = DOMUtils
1433:                                .getFirstChildElement(pTestCasePlanElement);
1434:                        while (lTestCaseSubElement != null
1435:                                && lTestCaseSubElement.getTagName().equals(
1436:                                        "AcceptanceDocument") == false)
1437:                            lTestCaseSubElement = DOMUtils
1438:                                    .getNextSiblingElement(lTestCaseSubElement);
1439:                        if (lTestCaseSubElement != null) {
1440:                            Element lTargetAcceptanceDocumentElement = (Element) pTemplateContext.mTestCaseLogElement
1441:                                    .appendChild(pTemplateContext.mTestLogDocument
1442:                                            .createElement("AcceptanceDocument"));
1443:                            copyChildElementsWithoutNamespacesWithTemplates(
1444:                                    lTargetAcceptanceDocumentElement,
1445:                                    lTestCaseSubElement, pTemplateContext);
1446:                            // Now - analyse acceptance element and determine whether test step outcome has to be overturned
1447:
1448:                            // This check is done first - so errors are always reported
1449:                            // Presence of any ErrorMessages will indicate that result status has to be forced to acceptance failure
1450:
1451:                            // This check is done second
1452:                            // Presence of any AcceptanceMessages will indicate that result status has to be forced acceptance success
1453:
1454:                            NodeList lErrorMessagesList = lTargetAcceptanceDocumentElement
1455:                                    .getElementsByTagName("ErrorMessage");
1456:                            NodeList lAcceptanceMessagesList = lTargetAcceptanceDocumentElement
1457:                                    .getElementsByTagName("AcceptanceMessage");
1458:                            if (lErrorMessagesList.getLength() > 0)
1459:                                pTemplateContext.mTestCaseLogElement
1460:                                        .setAttribute("status",
1461:                                                "AcceptanceFailure");
1462:                            else if (lAcceptanceMessagesList.getLength() > 0)
1463:                                pTemplateContext.mTestCaseLogElement
1464:                                        .setAttribute("status", "Success");
1465:                            // If none of these messages present - result should be left alone
1466:                            // which will leave it as Exception failure for the exceptions and
1467:                            // success for all other cases	
1468:                        }
1469:                        // If Acceptance document is not present - result should be left alone
1470:                        // which will leave it as TestStepFailure for the test step failures and success for all other cases	
1471:                        // Create performance record for the test case if logging of the test performance is on
1472:                        if (mLogTestPerformance)
1473:                            appendPerformanceElement(
1474:                                    pTemplateContext.mTestCaseLogElement,
1475:                                    lTestCaseStart, new Date());
1476:                        // Now work on sleep after
1477:                        if (pTestCasePlanElement.hasAttribute("sleepAfter")) {
1478:                            String lSecondsToSleep = pTestCasePlanElement
1479:                                    .getAttribute("sleepAfter");
1480:                            if (sLogger.isDebugEnabled())
1481:                                sLogger
1482:                                        .info("Will sleep for "
1483:                                                + lSecondsToSleep
1484:                                                + " seconds as defined in the sleepAfter attribute of the TestCase...");
1485:                            Thread.sleep((long) (Integer
1486:                                    .parseInt(lSecondsToSleep) * 1000));
1487:                            pTemplateContext.mTestCaseLogElement.setAttribute(
1488:                                    "sleepAfter", lSecondsToSleep);
1489:                        }
1490:                        // Log information about this test case
1491:                        sLogger.info(lLogIndent
1492:                                + "Completed "
1493:                                + pTestCasePlanElement.getAttribute("name")
1494:                                + " TestCase. Status: "
1495:                                + pTemplateContext.mTestCaseLogElement
1496:                                        .getAttribute("status"));
1497:                    }
1498:                    return pTemplateContext.mTestCaseLogElement;
1499:                } finally {
1500:                    // Restore the previous element on a stack if the current element is ours
1501:                    if (lTestCaseLogElement != null
1502:                            && pTemplateContext.mTestCaseLogElement == lTestCaseLogElement) {
1503:                        if (pTemplateContext.mTestCaseLogElementStack.size() > 0)
1504:                            pTemplateContext.mTestCaseLogElement = (Element) pTemplateContext.mTestCaseLogElementStack
1505:                                    .remove(0);
1506:                        else
1507:                            pTemplateContext.mTestCaseLogElement = null;
1508:                    }
1509:                }
1510:            }
1511:
1512:            /** Operation invocation functionality, processes given Operation element and populates results back into the target element */
1513:            public void processOperationPlan(Element pTargetElement,
1514:                    Element pOperationPlanElement,
1515:                    TemplateContext pTemplateContext) throws Exception {
1516:                Element lTargetOperationLogElement = (Element) pTemplateContext.mTestCaseLogElement
1517:                        .appendChild(pTemplateContext.mTestLogDocument
1518:                                .createElement("OperationLog"));
1519:                copyBaseElements(pOperationPlanElement,
1520:                        lTargetOperationLogElement, pTemplateContext);
1521:
1522:                // Process InputDocument
1523:                Element lSourceInputDocumentElement = DOMUtils
1524:                        .getFirstChildElement(pOperationPlanElement);
1525:                if (lSourceInputDocumentElement == null
1526:                        || lSourceInputDocumentElement.getTagName().equals(
1527:                                "InputDocument") == false)
1528:                    throw new Exception(
1529:                            "OperationPlan element must contain InputDocument element, which is used to specify an input to the operation.");
1530:                // Default scope is for templates inside InputDocument is TestCase
1531:                Element lTargetInputDocumentElement = (Element) lTargetOperationLogElement
1532:                        .appendChild(pTemplateContext.mTestLogDocument
1533:                                .createElement("InputDocument"));
1534:                copyChildElementsWithoutNamespacesWithTemplates(
1535:                        lTargetInputDocumentElement,
1536:                        lSourceInputDocumentElement, pTemplateContext);
1537:                Element lInputElement = DOMUtils
1538:                        .getFirstChildElement(lTargetInputDocumentElement);
1539:                if (lInputElement == null)
1540:                    throw new Exception(
1541:                            "The InputDocument is empty and can not be interpreted correctly.");
1542:                // Now prepare actual input document and run it		
1543:                Document lTestInputDocument = mScenarioDocumentBuilder
1544:                        .newDocument();
1545:                lTestInputDocument.appendChild(lTestInputDocument.importNode(
1546:                        lInputElement, true));
1547:                DOMSource lDOMSource = new DOMSource(lTestInputDocument);
1548:
1549:                Transformer lTransformer = mTransformerFactory.newTransformer();
1550:                lTransformer.setOutputProperty(OutputKeys.METHOD, "xml");
1551:                lTransformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
1552:                // Transform with indent for the file and display if debug is on
1553:                if (sLogger.isDebugEnabled()) {
1554:                    StringWriter lIndentedContents = new StringWriter();
1555:                    lTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
1556:                    lTransformer.transform(lDOMSource, new StreamResult(
1557:                            lIndentedContents));
1558:                    // Display message
1559:                    sLogger
1560:                            .debug("Running operation with following inputs:\r\n"
1561:                                    + lIndentedContents.toString());
1562:                }
1563:                lTransformer.setOutputProperty(OutputKeys.INDENT, "no");
1564:                StringWriter lRawContents = new StringWriter();
1565:                lTransformer.transform(lDOMSource, new StreamResult(
1566:                        lRawContents));
1567:
1568:                // Find the runner for the test			
1569:                String lInputNamespace = lInputElement.getNamespaceURI();
1570:                if (lInputNamespace == null)
1571:                    throw new Exception(
1572:                            "Namespace attribute is missing on operation input element.");
1573:                AdapterRunner lRunner = (AdapterRunner) mAdapterRunners
1574:                        .get(lInputNamespace);
1575:                if (lRunner == null)
1576:                    mAdapterRunners.put(lInputNamespace,
1577:                            lRunner = new AdapterRunner(lInputNamespace));
1578:                Date lOperationStart = new Date();
1579:                String lResultFileContents = lRunner
1580:                        .executeOperation(lRawContents.toString());
1581:                Date lOperationEnd = new Date();
1582:                Document lTestOutputDocument = mAnyDocumentBuilder
1583:                        .parse(new InputSource(new StringReader(
1584:                                lResultFileContents)));
1585:                Element lOperationResultElement = lTestOutputDocument
1586:                        .getDocumentElement();
1587:                Element lOutputDocumentElement = (Element) lTargetOperationLogElement
1588:                        .appendChild(pTemplateContext.mTestLogDocument
1589:                                .createElement("OutputDocument"));
1590:                lOutputDocumentElement
1591:                        .appendChild(pTemplateContext.mTestLogDocument
1592:                                .importNode(lOperationResultElement, true));
1593:                // Log the test output
1594:                if (sLogger.isDebugEnabled()) {
1595:                    StringWriter lIndentedResultFileContents = new StringWriter();
1596:                    lTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
1597:                    lTransformer.transform(new DOMSource(lTestOutputDocument),
1598:                            new StreamResult(lIndentedResultFileContents));
1599:                    sLogger
1600:                            .debug("Operation has returned following output:\r\n"
1601:                                    + lIndentedResultFileContents);
1602:                }
1603:                // We append performance element only in case when there was no exception
1604:                // This will ensure the relevance of the performance document on this level
1605:                if (mLogTestPerformance)
1606:                    appendPerformanceElement(lTargetOperationLogElement,
1607:                            lOperationStart, lOperationEnd);
1608:                // Test if operation contains a failure indicator
1609:                if (!isOperationSuccessful(lOperationResultElement)) {
1610:                    // Change the status of the test case	
1611:                    pTemplateContext.mTestCaseLogElement.setAttribute("status",
1612:                            "OperationFailure");
1613:                }
1614:            }
1615:
1616:            /** Subscription invocation functionality, processes given SubscriptionPlan element and populates results back into the target element */
1617:            public void processSubscriptionPlan(Element pTargetElement,
1618:                    Element pSubscriptionPlanElement,
1619:                    TemplateContext pTemplateContext) throws Exception {
1620:                // Process SubscriptionPlan element
1621:                Element lTargetSubscriptionLogElement = (Element) pTemplateContext.mTestCaseLogElement
1622:                        .appendChild(pTemplateContext.mTestLogDocument
1623:                                .createElement("SubscriptionLog"));
1624:                copyBaseElements(pSubscriptionPlanElement,
1625:                        lTargetSubscriptionLogElement, pTemplateContext);
1626:
1627:                // Process SubscriptionOperationPlan element
1628:                Element lSubscriptionOperationPlanElement = DOMUtils
1629:                        .getFirstChildElement(pSubscriptionPlanElement);
1630:                if (lSubscriptionOperationPlanElement == null
1631:                        || lSubscriptionOperationPlanElement.getTagName()
1632:                                .equals("SubscriptionOperationPlan") == false)
1633:                    throw new Exception(
1634:                            "SubscriptionPlan element must contain SubscriptionOperationPlan element, which is used to specify details of the subscription operation.");
1635:                Element lTargetSubscriptionOperationLogElement = (Element) lTargetSubscriptionLogElement
1636:                        .appendChild(pTemplateContext.mTestLogDocument
1637:                                .createElement("SubscriptionOperationLog"));
1638:                copyBaseElements(lSubscriptionOperationPlanElement,
1639:                        lTargetSubscriptionOperationLogElement,
1640:                        pTemplateContext);
1641:
1642:                // Process InputDocument element
1643:                Element lSourceInputDocumentElement = DOMUtils
1644:                        .getFirstChildElement(lSubscriptionOperationPlanElement);
1645:                if (lSourceInputDocumentElement == null
1646:                        || lSourceInputDocumentElement.getTagName().equals(
1647:                                "InputDocument") == false)
1648:                    throw new Exception(
1649:                            "SubscriptionOperationPlan element must contain InputDocument element, which is used to specify an input to the operation.");
1650:
1651:                // Default scope is for templates inside InputDocument is TestCase
1652:                Element lTargetInputDocumentElement = (Element) lTargetSubscriptionOperationLogElement
1653:                        .appendChild(pTemplateContext.mTestLogDocument
1654:                                .createElement("InputDocument"));
1655:                copyChildElementsWithoutNamespacesWithTemplates(
1656:                        lTargetInputDocumentElement,
1657:                        lSourceInputDocumentElement, pTemplateContext);
1658:                Element lInputElement = DOMUtils
1659:                        .getFirstChildElement(lTargetInputDocumentElement);
1660:                if (lInputElement == null)
1661:                    throw new Exception(
1662:                            "The InputDocument is empty and can not be interpreted correctly.");
1663:
1664:                // Now prepare actual input document and run it		
1665:                Document lTestInputDocument = mScenarioDocumentBuilder
1666:                        .newDocument();
1667:                lTestInputDocument.appendChild(lTestInputDocument.importNode(
1668:                        lInputElement, true));
1669:                DOMSource lDOMSource = new DOMSource(lTestInputDocument);
1670:
1671:                Transformer lTransformer = mTransformerFactory.newTransformer();
1672:                lTransformer.setOutputProperty(OutputKeys.METHOD, "xml");
1673:                lTransformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
1674:                // Transform with indent for the file and display if debug is on
1675:                if (sLogger.isDebugEnabled()) {
1676:                    StringWriter lIndentedContents = new StringWriter();
1677:                    lTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
1678:                    lTransformer.transform(lDOMSource, new StreamResult(
1679:                            lIndentedContents));
1680:                    // Display message
1681:                    sLogger
1682:                            .debug("Running subscription operation with following inputs:\r\n"
1683:                                    + lIndentedContents.toString());
1684:                }
1685:                lTransformer.setOutputProperty(OutputKeys.INDENT, "no");
1686:                StringWriter lRawContents = new StringWriter();
1687:                lTransformer.transform(lDOMSource, new StreamResult(
1688:                        lRawContents));
1689:
1690:                // Find the runner for the test			
1691:                String lInputNamespace = lInputElement.getNamespaceURI();
1692:                if (lInputNamespace == null)
1693:                    throw new Exception(
1694:                            "Namespace attribute is missing on subscription operation input element.");
1695:
1696:                AdapterRunner lRunner = (AdapterRunner) mAdapterRunners
1697:                        .get(lInputNamespace);
1698:                if (lRunner == null)
1699:                    mAdapterRunners.put(lInputNamespace,
1700:                            lRunner = new AdapterRunner(lInputNamespace));
1701:                Date lOperationStart = new Date();
1702:                String lResultFileContents = lRunner.subscribe(lRawContents
1703:                        .toString(), pTemplateContext,
1704:                        lTargetSubscriptionLogElement);
1705:                Date lOperationEnd = new Date();
1706:                Document lTestOutputDocument = mAnyDocumentBuilder
1707:                        .parse(new InputSource(new StringReader(
1708:                                lResultFileContents)));
1709:                Element lOperationResultElement = lTestOutputDocument
1710:                        .getDocumentElement();
1711:                Element lOutputDocumentElement = (Element) lTargetSubscriptionOperationLogElement
1712:                        .appendChild(pTemplateContext.mTestLogDocument
1713:                                .createElement("OutputDocument"));
1714:                lOutputDocumentElement
1715:                        .appendChild(pTemplateContext.mTestLogDocument
1716:                                .importNode(lOperationResultElement, true));
1717:                // Log the test output
1718:                if (sLogger.isDebugEnabled()) {
1719:                    StringWriter lIndentedResultFileContents = new StringWriter();
1720:                    lTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
1721:                    lTransformer.transform(new DOMSource(lTestOutputDocument),
1722:                            new StreamResult(lIndentedResultFileContents));
1723:                    sLogger
1724:                            .debug("Operation has returned following output:\r\n"
1725:                                    + lIndentedResultFileContents);
1726:                }
1727:                // We append performance element only in case when there was no exception
1728:                // This will ensure the relevance of the performance document on this level
1729:                if (mLogTestPerformance)
1730:                    appendPerformanceElement(
1731:                            lTargetSubscriptionOperationLogElement,
1732:                            lOperationStart, lOperationEnd);
1733:                // Test if operation contains a failure indicator
1734:                if (!isOperationSuccessful(lOperationResultElement)) {
1735:                    // Change the status of the test case	
1736:                    pTemplateContext.mTestCaseLogElement.setAttribute("status",
1737:                            "SubscriptionOperationFailure");
1738:                }
1739:            }
1740:
1741:            /** Special functionality, processes given ValueOf element and populates results into the target element */
1742:            public void processValueOf(Element pTargetElement,
1743:                    Element pValueOfElement, TemplateContext pTemplateContext)
1744:                    throws Exception {
1745:                if (pValueOfElement.hasAttribute("select")) {
1746:                    // Output the result of the XPath select
1747:                    XPath path = new DOMXPath(pValueOfElement
1748:                            .getAttribute("select"));
1749:                    // Copy namespace specifications
1750:                    NamedNodeMap lAttributeNodes = pValueOfElement
1751:                            .getAttributes();
1752:                    int lAttributesCount = lAttributeNodes.getLength();
1753:                    for (int i = 0; i < lAttributesCount; i++) {
1754:                        Node lSourceAttributeNode = lAttributeNodes.item(i);
1755:                        String lNamespaceURI = lSourceAttributeNode
1756:                                .getNamespaceURI();
1757:                        if (lNamespaceURI != null
1758:                                && lNamespaceURI.equals(W3C_XMLNS_SCHEMA)) {
1759:                            String lAttributeName = lSourceAttributeNode
1760:                                    .getNodeName();
1761:                            if (lAttributeName != null
1762:                                    && lAttributeName.startsWith("xmlns:"))
1763:                                path.addNamespace(lAttributeName.substring(6),
1764:                                        lSourceAttributeNode.getNodeValue());
1765:                        }
1766:                    }
1767:                    List lResults = path
1768:                            .selectNodes(pTemplateContext.mTestScenarioLogElement);
1769:                    for (Iterator lResultsIter = lResults.iterator(); lResultsIter
1770:                            .hasNext();) {
1771:                        Object lNextResult = lResultsIter.next();
1772:                        if (lNextResult instanceof  String)
1773:                            pTargetElement.appendChild(pTargetElement
1774:                                    .getOwnerDocument().createTextNode(
1775:                                            (String) lNextResult));
1776:                        else if (lNextResult instanceof  Element)
1777:                            copyChildElementsWithoutNamespacesWithTemplates(
1778:                                    pTargetElement, (Element) lNextResult,
1779:                                    pTemplateContext);
1780:                        else
1781:                            throw new Exception(
1782:                                    "Unexpected type returned from the XPath search :"
1783:                                            + lNextResult.getClass().getName());
1784:                    }
1785:                } else if (pValueOfElement.hasAttribute("property")) {
1786:                    // Output the result of the XPath select
1787:                    String lPropertyText = System.getProperty(pValueOfElement
1788:                            .getAttribute("property"));
1789:                    if (lPropertyText == null)
1790:                        throw new Exception("Property '"
1791:                                + pValueOfElement.getAttribute("property")
1792:                                + "' is undefined.");
1793:                    pTargetElement.appendChild(pTargetElement
1794:                            .getOwnerDocument().createTextNode(lPropertyText));
1795:                } else
1796:                    throw new Exception(
1797:                            "Unable to interpret the ValueOf element. It does not contain any supported instruction.");
1798:            }
1799:
1800:            /** Special functionality, processes given Timestamp element and populates results into the target element */
1801:            public void processValueOfTimestamp(Element pTargetElement,
1802:                    Element pTimestampElement, TemplateContext pTemplateContext)
1803:                    throws Exception {
1804:                // Initialise timestamp and do some math
1805:                Calendar lTimestamp = Calendar.getInstance();
1806:                if (pTimestampElement.hasAttribute("addYear"))
1807:                    lTimestamp.add(Calendar.YEAR,
1808:                            Integer.parseInt(pTimestampElement
1809:                                    .getAttribute("addYear")));
1810:                if (pTimestampElement.hasAttribute("addMonth"))
1811:                    lTimestamp.add(Calendar.MONTH, Integer
1812:                            .parseInt(pTimestampElement
1813:                                    .getAttribute("addMonth")));
1814:                if (pTimestampElement.hasAttribute("addDay"))
1815:                    lTimestamp
1816:                            .add(Calendar.DATE, Integer
1817:                                    .parseInt(pTimestampElement
1818:                                            .getAttribute("addDay")));
1819:                if (pTimestampElement.hasAttribute("addHour"))
1820:                    lTimestamp.add(Calendar.HOUR_OF_DAY,
1821:                            Integer.parseInt(pTimestampElement
1822:                                    .getAttribute("addHour")));
1823:                if (pTimestampElement.hasAttribute("addMinute"))
1824:                    lTimestamp.add(Calendar.MINUTE, Integer
1825:                            .parseInt(pTimestampElement
1826:                                    .getAttribute("addMinute")));
1827:                if (pTimestampElement.hasAttribute("addSecond"))
1828:                    lTimestamp.add(Calendar.SECOND, Integer
1829:                            .parseInt(pTimestampElement
1830:                                    .getAttribute("addSecond")));
1831:                // Render the output
1832:                SimpleDateFormat lSimpleDateFormat = new SimpleDateFormat(
1833:                        pTimestampElement.getAttribute("format"));
1834:                String lTimestampExpresion = lSimpleDateFormat
1835:                        .format(lTimestamp.getTime());
1836:                pTargetElement.appendChild(pTargetElement.getOwnerDocument()
1837:                        .createTextNode(lTimestampExpresion));
1838:            }
1839:
1840:            /** Include processor functionality, processes given Include element and populates results back into the target element */
1841:            public void processInclude(Element pTargetElement,
1842:                    Element pTemplateElement, TemplateContext pTemplateContext)
1843:                    throws Exception {
1844:                if (mIncludePath == null)
1845:                    throw new Exception(
1846:                            "-includePath parameter must be specified for the <Include> instruction to work correctly");
1847:                // Get the file name
1848:                String lFileName = pTemplateElement.getAttribute("filename");
1849:                Document lInputDocument = null;
1850:                for (int i = 0; i < mIncludePath.length; i++) {
1851:                    String lAttemptedFileName = mIncludePath[i]
1852:                            + File.separator + lFileName;
1853:                    File lIncludeFile = new File(lAttemptedFileName);
1854:                    if (lIncludeFile.exists() && lIncludeFile.isFile()) {
1855:                        // Load the documentt
1856:                        lInputDocument = mAnyDocumentBuilder
1857:                                .parse(new InputSource(new FileReader(
1858:                                        lIncludeFile)));
1859:                        break;
1860:                    }
1861:                }
1862:                if (lInputDocument == null)
1863:                    throw new Exception("Unable to find include file '"
1864:                            + lFileName + "' anywhere on the include path.");
1865:                // Import the included document and make it the child of the include element
1866:                // Than call the copy routine recursively
1867:                Node lImportedNode = pTemplateElement.getOwnerDocument()
1868:                        .importNode(lInputDocument.getDocumentElement(), true);
1869:                pTemplateElement.appendChild(lImportedNode);
1870:                copyChildElementsWithoutNamespacesWithTemplates(pTargetElement,
1871:                        pTemplateElement, pTemplateContext);
1872:            }
1873:
1874:            /** Template processor functionality, processes given Template element and populates results back into the target element */
1875:            public void processTemplate(Element pTargetElement,
1876:                    Element pTemplateElement, TemplateContext pTemplateContext)
1877:                    throws Exception {
1878:                // Find out the document to use as a source document for the template
1879:                Element lSourceElement = null;
1880:                {
1881:                    String lScope = pTemplateElement.getAttribute("scope");
1882:                    if (lScope.equals("/")) {
1883:                        // Whole scenario
1884:                        lSourceElement = pTemplateContext.mTestScenarioLogElement;
1885:                    } else if (lScope.length() == 0 || lScope.equals(".")) {
1886:                        // Current test case (this is also the default)
1887:                        lSourceElement = pTemplateContext.mTestCaseLogElement;
1888:                    } else {
1889:                        // Series of ../ - each one referring to one higher level
1890:                        int lLevels = 0;
1891:                        while (lScope.startsWith("../")) {
1892:                            lLevels++;
1893:                            lScope = lScope.substring(3);
1894:                        }
1895:                        if (lScope.length() > 0)
1896:                            throw new Exception(
1897:                                    "Invalid format of scope attribute: "
1898:                                            + pTemplateElement
1899:                                                    .getAttribute("scope"));
1900:                        if (lLevels > pTemplateContext.mTestCaseLogElementStack
1901:                                .size())
1902:                            throw new Exception(
1903:                                    "Scope refers to not existant TestCase. Actual number of levels is "
1904:                                            + pTemplateContext.mTestCaseLogElementStack
1905:                                                    .size()
1906:                                            + " specified scope is "
1907:                                            + pTemplateElement
1908:                                                    .getAttribute("scope"));
1909:                        lSourceElement = (Element) pTemplateContext.mTestCaseLogElementStack
1910:                                .get(lLevels - 1);
1911:                    }
1912:                }
1913:
1914:                String lTemplateType = pTemplateElement.getAttribute("type");
1915:                if (lTemplateType.equals("XSLText"))
1916:                    processTemplateXSLText(pTargetElement, pTemplateElement,
1917:                            pTemplateContext, lSourceElement);
1918:                else if (lTemplateType.equals("XSLDocument"))
1919:                    processTemplateXSLDocument(pTargetElement,
1920:                            pTemplateElement, pTemplateContext, lSourceElement);
1921:                else
1922:                    throw new Exception(
1923:                            "Unrecognised value of the type attribute in the Template element: "
1924:                                    + lTemplateType);
1925:            }
1926:
1927:            /** Template processor functionality, processes given Template element and populates results back into the target element */
1928:            public void processTemplateXSLText(Element pTargetElement,
1929:                    Element pTemplateElement, TemplateContext pTemplateContext,
1930:                    Element pSourceElement) throws Exception {
1931:                // Copy all Text and CData nodels into one
1932:                StringBuffer lTemplateTextBuffer = new StringBuffer();
1933:                NodeList lChildNodes = pTemplateElement.getChildNodes();
1934:                int lChildrenCount = lChildNodes.getLength();
1935:                for (int i = 0; i < lChildrenCount; i++) {
1936:                    Node lChildNode = lChildNodes.item(i);
1937:                    if (lChildNode.getNodeType() == Element.TEXT_NODE
1938:                            || lChildNode.getNodeType() == Element.CDATA_SECTION_NODE)
1939:                        lTemplateTextBuffer.append(lChildNode.getNodeValue());
1940:                    else
1941:                        throw new Exception(
1942:                                "The Template element with type XSLText must only contain text or CDATA child nodes.");
1943:                }
1944:                String lTemplateText = lTemplateTextBuffer.toString().trim();
1945:                if (!lTemplateText.startsWith("<xsl:stylesheet"))
1946:                    throw new Exception(
1947:                            "XSLText Template element must have a child stylesheet definition text. Found:"
1948:                                    + lTemplateText);
1949:                // Build a reasonable document and parse it
1950:                StringBuffer lTemplateDocumentText = new StringBuffer();
1951:                lTemplateDocumentText
1952:                        .append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
1953:                lTemplateDocumentText.append("<Template xmlns=\"");
1954:                lTemplateDocumentText.append(METABOSS_SCENARIO_RUNNER_SCHEMA);
1955:                lTemplateDocumentText.append("\" xmlns:xsl=\"");
1956:                lTemplateDocumentText.append(W3C_XSLT_SCHEMA);
1957:                lTemplateDocumentText.append("\">");
1958:                lTemplateDocumentText.append(lTemplateText);
1959:                lTemplateDocumentText.append("</Template>");
1960:                Document lTemplateDocument = mScenarioDocumentBuilder
1961:                        .parse(new InputSource(new StringReader(
1962:                                lTemplateDocumentText.toString())));
1963:                processTemplateXSLDocument(pTargetElement, lTemplateDocument
1964:                        .getDocumentElement(), pTemplateContext, pSourceElement);
1965:            }
1966:
1967:            /** Template processor functionality, processes given Template element and populates results back into the target element */
1968:            public void processTemplateXSLDocument(Element pTargetElement,
1969:                    Element pTemplateElement, TemplateContext pTemplateContext,
1970:                    Element pSourceElement) throws Exception {
1971:                // Prepared stylesheet document for use as a template
1972:                NodeList lStylesheetElementsList = pTemplateElement
1973:                        .getElementsByTagNameNS(W3C_XSLT_SCHEMA, "stylesheet");
1974:                if (lStylesheetElementsList.getLength() == 0)
1975:                    throw new Exception(
1976:                            "Template element does not have a child stylesheet element.");
1977:                Element lStylesheetElement = (Element) lStylesheetElementsList
1978:                        .item(0);
1979:
1980:                if (!lStylesheetElement.getTagName().equals("xsl:stylesheet"))
1981:                    throw new Exception(
1982:                            "XSL Template element must have a child stylesheet element. Found: "
1983:                                    + lStylesheetElement.getTagName());
1984:                // Ensure that the namespaces are setup in this element
1985:                lStylesheetElement.setAttributeNS(W3C_XMLNS_SCHEMA, "xmlns",
1986:                        METABOSS_SCENARIO_RUNNER_SCHEMA);
1987:                lStylesheetElement.setAttribute("xmlns:xsl", W3C_XSLT_SCHEMA);
1988:
1989:                // Try to transform template to string
1990:                StringWriter lRawTemplateContents = new StringWriter();
1991:                //		mTransformerFactory.setAttribute("debug",Boolean.TRUE);
1992:                Transformer lTemplateTransformer = mTransformerFactory
1993:                        .newTransformer();
1994:                lTemplateTransformer
1995:                        .setOutputProperty(OutputKeys.METHOD, "xml");
1996:                lTemplateTransformer.setOutputProperty(OutputKeys.STANDALONE,
1997:                        "yes");
1998:                lTemplateTransformer.setOutputProperty(OutputKeys.INDENT, "no");
1999:                lTemplateTransformer.transform(
2000:                        new DOMSource(lStylesheetElement), new StreamResult(
2001:                                lRawTemplateContents));
2002:                // Perform transformation to string buffer and than invoke parser
2003:                // this should convert contents of CDATA to what they should be
2004:                Transformer lTransformer = mTransformerFactory
2005:                        .newTransformer(new StreamSource(new StringReader(
2006:                                lRawTemplateContents.toString())));
2007:                lTransformer.setOutputProperty(OutputKeys.METHOD, "xml");
2008:                lTransformer.setOutputProperty(OutputKeys.STANDALONE, "no");
2009:                lTransformer.setOutputProperty(OutputKeys.INDENT, "no");
2010:                lTransformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,
2011:                        "yes");
2012:                StringWriter lRawContents = new StringWriter();
2013:                lTransformer.transform(new DOMSource(pSourceElement),
2014:                        new StreamResult(lRawContents));
2015:                Document lResultDocument = mTransformationResultDocumentBuilder
2016:                        .parse(new InputSource(new StringReader(
2017:                                "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><ArtificalRoot>"
2018:                                        + lRawContents.toString()
2019:                                        + "</ArtificalRoot>")));
2020:
2021:                // Copy result elements back
2022:                //		for (Node lChildNode = lResultDocument.getDocumentElement().getFirstChild(); lChildNode != null; lChildNode = lChildNode.getNextSibling())
2023:                //		{
2024:                //			if (lChildNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE)
2025:                //				pTargetElement.appendChild(pTargetElement.getOwnerDocument().importNode(lChildNode, true));
2026:                //		}
2027:                for (Node lChildNode = lResultDocument.getDocumentElement()
2028:                        .getFirstChild(); lChildNode != null; lChildNode = lChildNode
2029:                        .getNextSibling())
2030:                    importElementWithoutNamespace(pTargetElement, lChildNode);
2031:            }
2032:
2033:            public static void main(String[] args) {
2034:                try {
2035:                    // Configure logger as early as possible
2036:                    org.apache.log4j.PropertyConfigurator.configure(System
2037:                            .getProperties());
2038:                    sScenarioRunnerInstance = new ScenarioRunner();
2039:                    if (args != null) {
2040:                        for (int i = 0; i < args.length; i++) {
2041:                            String lArg = args[i];
2042:                            if (lArg.startsWith("-scenarioPath="))
2043:                                sScenarioRunnerInstance.setScenarioPath(lArg
2044:                                        .substring(14));
2045:                            else if (lArg.startsWith("-includePath="))
2046:                                sScenarioRunnerInstance.setIncludePath(lArg
2047:                                        .substring(13));
2048:                            else if (lArg.startsWith("-scenarioName="))
2049:                                sScenarioRunnerInstance.setScenarioName(lArg
2050:                                        .substring(14));
2051:                            else if (lArg.startsWith("-scenarioRunName="))
2052:                                sScenarioRunnerInstance.setScenarioRunName(lArg
2053:                                        .substring(17));
2054:                            else if (lArg.startsWith("-clientPath="))
2055:                                sScenarioRunnerInstance.setClientPath(lArg
2056:                                        .substring(12));
2057:                            else if (lArg.startsWith("-loggingPath="))
2058:                                sScenarioRunnerInstance.setLoggingPath(lArg
2059:                                        .substring(13));
2060:                            else if (lArg.startsWith("-logTestPerformance="))
2061:                                sScenarioRunnerInstance
2062:                                        .setLogTestPerformance(Boolean.valueOf(
2063:                                                lArg.substring(19))
2064:                                                .booleanValue());
2065:                            else if (lArg.startsWith("-specimenFile="))
2066:                                sScenarioRunnerInstance.setSpecimenFile(lArg
2067:                                        .substring(14));
2068:                            else
2069:                                throw new IllegalArgumentException(
2070:                                        "Unrecognised argument: " + lArg);
2071:                        }
2072:                    }
2073:                    // Insert shutdown hook which will save the document if it has not been saved before
2074:                    // this should help to save files when test has locked up and has to be aborted
2075:                    Runtime.getRuntime().addShutdownHook(
2076:                            new LogFileGuardingThread());
2077:
2078:                    System.exit(sScenarioRunnerInstance.runScenario() ? 0 : 1);
2079:                } catch (Throwable t) {
2080:                    t.printStackTrace();
2081:                    System.exit(2);
2082:                }
2083:            }
2084:
2085:            // Helper. Copies entire element from source to target and looses default system tester namespace     
2086:            private static Node importElementWithoutNamespace(
2087:                    Node lTargetParentNode, Node lSourceNode) {
2088:                Document lTargetDocument = lTargetParentNode.getOwnerDocument();
2089:
2090:                if (lSourceNode.getNodeType() == Node.ELEMENT_NODE) {
2091:                    String lSourceElementNamespaceURI = lSourceNode
2092:                            .getNamespaceURI();
2093:                    Element lTargetElement = null;
2094:                    if (lSourceElementNamespaceURI == null
2095:                            || lSourceElementNamespaceURI
2096:                                    .equals(METABOSS_SCENARIO_RUNNER_SCHEMA))
2097:                        lTargetElement = (Element) lTargetParentNode
2098:                                .appendChild(lTargetDocument
2099:                                        .createElement(((Element) lSourceNode)
2100:                                                .getTagName()));
2101:                    else
2102:                        lTargetElement = (Element) lTargetParentNode
2103:                                .appendChild(lTargetDocument.createElementNS(
2104:                                        lSourceElementNamespaceURI,
2105:                                        ((Element) lSourceNode).getTagName()));
2106:                    NamedNodeMap lAttributeNodes = lSourceNode.getAttributes();
2107:                    int lAttributesCount = lAttributeNodes.getLength();
2108:                    for (int i = 0; i < lAttributesCount; i++) {
2109:                        Node lSourceAttributeNode = lAttributeNodes.item(i);
2110:                        String lSourceAttributeNodeNamespaceURI = lSourceAttributeNode
2111:                                .getNamespaceURI();
2112:                        if (lSourceAttributeNodeNamespaceURI == null
2113:                                || lSourceAttributeNodeNamespaceURI
2114:                                        .equals(METABOSS_SCENARIO_RUNNER_SCHEMA))
2115:                            lTargetElement.setAttribute(lSourceAttributeNode
2116:                                    .getLocalName(), lSourceAttributeNode
2117:                                    .getNodeValue());
2118:                        else
2119:                            lTargetElement
2120:                                    .setAttributeNodeNS((Attr) lTargetDocument
2121:                                            .importNode(lSourceAttributeNode,
2122:                                                    true));
2123:                    }
2124:                    NodeList lSourceChildNodes = lSourceNode.getChildNodes();
2125:                    int lChildrenCount = lSourceChildNodes.getLength();
2126:                    for (int i = 0; i < lChildrenCount; i++)
2127:                        importElementWithoutNamespace(lTargetElement,
2128:                                lSourceChildNodes.item(i));
2129:                    return lTargetElement;
2130:                } else
2131:                    return lTargetParentNode.appendChild(lTargetDocument
2132:                            .importNode(lSourceNode, true));
2133:            }
2134:
2135:            // Helper. Copies entire element from source to target and looses default system tester namespace     
2136:            private Element copyElementWithoutNamespaceWithTemplates(
2137:                    Element pTargetParentElement, Element pSourceElement,
2138:                    TemplateContext pTemplateContext) throws Exception {
2139:                Document lTargetDocument = pTargetParentElement
2140:                        .getOwnerDocument();
2141:
2142:                String lSourceElementNamespaceURI = pSourceElement
2143:                        .getNamespaceURI();
2144:                Element lTargetElement = null;
2145:                if (lSourceElementNamespaceURI == null
2146:                        || lSourceElementNamespaceURI
2147:                                .equals(METABOSS_SCENARIO_RUNNER_SCHEMA))
2148:                    lTargetElement = (Element) pTargetParentElement
2149:                            .appendChild(lTargetDocument
2150:                                    .createElement(pSourceElement.getTagName()));
2151:                else
2152:                    lTargetElement = (Element) pTargetParentElement
2153:                            .appendChild(lTargetDocument.createElementNS(
2154:                                    lSourceElementNamespaceURI, pSourceElement
2155:                                            .getTagName()));
2156:                NamedNodeMap lAttributeNodes = pSourceElement.getAttributes();
2157:                int lAttributesCount = lAttributeNodes.getLength();
2158:                for (int i = 0; i < lAttributesCount; i++) {
2159:                    Node lSourceAttributeNode = lAttributeNodes.item(i);
2160:                    String lSourceAttributeNodeNamespaceURI = lSourceAttributeNode
2161:                            .getNamespaceURI();
2162:                    if (lSourceAttributeNodeNamespaceURI == null
2163:                            || lSourceAttributeNodeNamespaceURI
2164:                                    .equals(METABOSS_SCENARIO_RUNNER_SCHEMA))
2165:                        lTargetElement.setAttribute(lSourceAttributeNode
2166:                                .getNodeName(), lSourceAttributeNode
2167:                                .getNodeValue());
2168:                    else
2169:                        lTargetElement
2170:                                .setAttributeNodeNS((Attr) lTargetDocument
2171:                                        .importNode(lSourceAttributeNode, true));
2172:                }
2173:                // Now copy child elements
2174:                copyChildElementsWithoutNamespacesWithTemplates(lTargetElement,
2175:                        pSourceElement, pTemplateContext);
2176:
2177:                return lTargetElement;
2178:            }
2179:
2180:            // Helper. Returns document, where system tester elements are present without namespace
2181:            // Our problem is that the test plan documents are done in default system tester namespace
2182:            // but some times it is not default in the parsed documents and may even copy itself onto the log document
2183:            // , which may stuff up the templates and transformation. So what we do is immediately
2184:            // drop the default namespace. It also allows to use any elements inside the
2185:            // ParametersDocuments etc.
2186:            private Document parseDocumentWithoutNamespace(
2187:                    InputSource pDocumentInputSource) throws SAXException,
2188:                    IOException {
2189:                // Load test definition into dom document
2190:                Document lNamespacedDocument = mScenarioDocumentBuilder
2191:                        .parse(pDocumentInputSource);
2192:                // Create clean document, convert root node and call import elements routine
2193:                Document lCleanDocument = mAnyDocumentBuilder.newDocument();
2194:                Element lSourceRootElement = lNamespacedDocument
2195:                        .getDocumentElement();
2196:                String lSourceRootElementNamespaceURI = lSourceRootElement
2197:                        .getNamespaceURI();
2198:                Element lTargetRootElement = null;
2199:                if (lSourceRootElementNamespaceURI == null
2200:                        || lSourceRootElementNamespaceURI
2201:                                .equals(METABOSS_SCENARIO_RUNNER_SCHEMA))
2202:                    lTargetRootElement = (Element) lCleanDocument
2203:                            .appendChild(lCleanDocument
2204:                                    .createElement(lSourceRootElement
2205:                                            .getTagName()));
2206:                else
2207:                    lTargetRootElement = (Element) lCleanDocument
2208:                            .appendChild(lCleanDocument.createElementNS(
2209:                                    lSourceRootElementNamespaceURI,
2210:                                    lSourceRootElement.getTagName()));
2211:                NamedNodeMap lAttributeNodes = lSourceRootElement
2212:                        .getAttributes();
2213:                int lAttributesCount = lAttributeNodes.getLength();
2214:                for (int i = 0; i < lAttributesCount; i++) {
2215:                    Node lSourceAttributeNode = lAttributeNodes.item(i);
2216:                    String lSourceAttributeNodeNamespaceURI = lSourceAttributeNode
2217:                            .getNamespaceURI();
2218:                    if (lSourceAttributeNodeNamespaceURI == null
2219:                            || lSourceAttributeNodeNamespaceURI
2220:                                    .equals(METABOSS_SCENARIO_RUNNER_SCHEMA))
2221:                        lTargetRootElement.setAttribute(lSourceAttributeNode
2222:                                .getLocalName(), lSourceAttributeNode
2223:                                .getNodeValue());
2224:                    else
2225:                        lTargetRootElement
2226:                                .setAttributeNodeNS((Attr) lCleanDocument
2227:                                        .importNode(lSourceAttributeNode, true));
2228:                }
2229:                NodeList lSourceChildNodes = lSourceRootElement.getChildNodes();
2230:                int lChildrenCount = lSourceChildNodes.getLength();
2231:                for (int i = 0; i < lChildrenCount; i++)
2232:                    importElementWithoutNamespace(lTargetRootElement,
2233:                            lSourceChildNodes.item(i));
2234:                // That's all			
2235:                return lCleanDocument;
2236:            }
2237:
2238:            // Helper. Copies all elements from source to target with optional template processing     
2239:            private void copyChildElementsWithoutNamespacesWithTemplates(
2240:                    Element pTargetLogElement, Element pSourceParentElement,
2241:                    TemplateContext pTemplateContext) throws Exception {
2242:                Document lTargetDocument = pTargetLogElement.getOwnerDocument();
2243:
2244:                // Iterate through all nodes - process elements in a special way and copy all other ones
2245:                NodeList lSourceChildNodes = pSourceParentElement
2246:                        .getChildNodes();
2247:                int lChildrenCount = lSourceChildNodes.getLength();
2248:                for (int i = 0; i < lChildrenCount; i++) {
2249:                    Node lChildNode = lSourceChildNodes.item(i);
2250:                    int lNodeType = lChildNode.getNodeType();
2251:                    if (lNodeType == Node.ELEMENT_NODE) {
2252:                        Element lChildElement = (Element) lChildNode;
2253:                        // See if we need to do special processing
2254:                        String lChildElementNamespaceURI = lChildElement
2255:                                .getNamespaceURI();
2256:                        if (lChildElementNamespaceURI == null
2257:                                || lChildElementNamespaceURI
2258:                                        .equals(METABOSS_SCENARIO_RUNNER_SCHEMA)) {
2259:                            // All special elements are inside default namespace or explicit MetaBoss namespace
2260:                            if (lChildElement.getTagName().equals("Template"))
2261:                                processTemplate(pTargetLogElement,
2262:                                        lChildElement, pTemplateContext);
2263:                            else if (lChildElement.getTagName().equals(
2264:                                    "Include"))
2265:                                processInclude(pTargetLogElement,
2266:                                        lChildElement, pTemplateContext);
2267:                            else if (lChildElement.getTagName().equals(
2268:                                    "ValueOf"))
2269:                                processValueOf(pTargetLogElement,
2270:                                        lChildElement, pTemplateContext);
2271:                            else if (lChildElement.getTagName().equals(
2272:                                    "ValueOfTimestamp"))
2273:                                processValueOfTimestamp(pTargetLogElement,
2274:                                        lChildElement, pTemplateContext);
2275:                            else
2276:                                copyElementWithoutNamespaceWithTemplates(
2277:                                        pTargetLogElement, lChildElement,
2278:                                        pTemplateContext);
2279:                        } else
2280:                            copyElementWithoutNamespaceWithTemplates(
2281:                                    pTargetLogElement, lChildElement,
2282:                                    pTemplateContext);
2283:                    } else
2284:                        pTargetLogElement.appendChild(lTargetDocument
2285:                                .importNode(lChildNode, true));
2286:                }
2287:            }
2288:
2289:            // Copyes base element attributes from source to target
2290:            private void copyBaseElements(Element pSourceElement,
2291:                    Element pTargetElement, TemplateContext pTemplateContext)
2292:                    throws Exception {
2293:                if (pSourceElement.hasAttribute("name"))
2294:                    pTargetElement.setAttribute("name", pSourceElement
2295:                            .getAttribute("name"));
2296:                if (pSourceElement.hasAttribute("id")) {
2297:                    pTargetElement.setAttribute("id", pSourceElement
2298:                            .getAttribute("id"));
2299:                    // Verify that id is unique
2300:                    if (!pTemplateContext.mUsedIds.add(pSourceElement
2301:                            .getAttribute("id")))
2302:                        throw new Exception(
2303:                                "The value of the element id attribute must be unique throughout whole test scenario. Id value '"
2304:                                        + pSourceElement.getAttribute("id")
2305:                                        + "' is used at least twice in the scenario.");
2306:                }
2307:                if (pSourceElement.hasAttribute("description"))
2308:                    pTargetElement.setAttribute("description", pSourceElement
2309:                            .getAttribute("description"));
2310:            }
2311:
2312:            // Helper. Will look for occurrence of element <IsSuccessful>false</IsSuccessful> at any depth in any namespace
2313:            // in the given element. Will return false if it is found. This allows to find out whether operation has failed or not
2314:            private boolean isOperationSuccessful(
2315:                    Element pOperationResultElementToTest) throws Exception {
2316:                // The result element from the structure must have <IsSuccessfull> element as an immediate child
2317:                for (Element lChildElement = DOMUtils
2318:                        .getFirstChildElement(pOperationResultElementToTest); lChildElement != null; lChildElement = DOMUtils
2319:                        .getNextSiblingElement(lChildElement)) {
2320:                    if (lChildElement.getTagName().equals("IsSuccessful")) {
2321:                        NodeList lChildNodes = lChildElement.getChildNodes();
2322:                        if (lChildNodes.getLength() == 1) {
2323:                            Node lFirstChild = lChildNodes.item(0);
2324:                            if (lFirstChild != null
2325:                                    && lFirstChild.getNodeType() == Node.TEXT_NODE) {
2326:                                String lNodeValue = lFirstChild.getNodeValue();
2327:                                if (lNodeValue != null) {
2328:                                    if (lNodeValue.equals("false"))
2329:                                        return false; // Operation appears to have failed
2330:                                    else if (lNodeValue.equals("true"))
2331:                                        return true; // Operation appears to have succeeded
2332:                                }
2333:                            }
2334:                        }
2335:                        throw new Exception(
2336:                                "Malformed operation result. The result element contains invalid <IsSuccessful> element. It is expected to only contain 'true' or 'false' string.");
2337:                    }
2338:                }
2339:                throw new Exception(
2340:                        "Malformed operation result. The result element does not contain <IsSuccessful> elements, which is used to analyse the outcome of the operation.");
2341:            }
2342:
2343:            private static class LogFileGuardingThread extends Thread {
2344:                public void run() {
2345:                    try {
2346:                        if (sScenarioRunnerInstance != null)
2347:                            sScenarioRunnerInstance
2348:                                    .saveScenarioLogIfNecessary();
2349:                    } catch (Throwable t) {
2350:                        sLogger
2351:                                .error("Unable to save the scenario log file",
2352:                                        t);
2353:                    }
2354:                }
2355:            }
2356:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.