Hi All,

I've put together a patch that allows the Test Recorder to perform playback against multiple webapps. What this means is that a category, or suite, like 'drt' can be run against the core webapp and the jsf webapp and the results will be displayed in a single JUnit report. This feature will allow us to run drts or bvts against all, or a selection of, webapps with a single command and generate a single JUnit report. The feature is fully implemented in the patch but the ant build files have not been modified to take advantage of the feature.

In order to implement this feature a new config file is required by the client side of the tool. The XML config file can be found here: .../netui/test/conf/testRecorder-server.xml, and it describes how to contact the server and the webapp context for each webapp. The test recorder client uses the config file to contact each webapp and obtain the full configuration for that webapp via HTTP.

I also cleaned up a few items while I was at it:
* two HTTP sessions are now used by the Test Recorder, instead of two sessions per test.
* removed some unnecessary jars from the test recorder build classpath.
* cleaned up ant files used to invoke the test recorder playback


Send any questions or comments my way.

Regards,
Patrick.
Index: trunk/netui/test/webapps/testRecorder-test/build.xml
===================================================================
--- trunk/netui/test/webapps/testRecorder-test/build.xml        (revision 36180)
+++ trunk/netui/test/webapps/testRecorder-test/build.xml        (working copy)
@@ -21,6 +21,7 @@
 
     <property name="webapp.name" value="testRecorder-test"/>
     <property name="testRecorder.config.name" value="${webapp.name}-config"/>
+    <property name="webapp.waitfor.url" 
value="http://localhost:8080/${webapp.name}"/>
 
     <!-- ================================================================ -->
     <!--                                                                  -->
@@ -64,15 +65,18 @@
         <ant antfile="${test.dir}/ant/testRecorder.xml" 
target="suite.callback" inheritAll="false">
             <property name="testRecorder.config.name" 
value="${testRecorder.config.name}"/>
             <property name="suite.name" value="test"/>
+            <property name="playback.webapps" value="testRecorder"/>
+            <property name="waitfor.url" value="${webapp.waitfor.url}"/>
         </ant>
     </target>
 
     <target name="test" description="Run a test suite with full server start / 
stop support.">
         <ant antfile="${test.dir}/ant/testRecorder.xml" inheritAll="false" 
target="server.test">
             <property name="app.build.file" 
location="${app.dir}/testRecorder-test/build.xml"/>
-            <property name="waitfor.url" 
value="http://localhost:8080/${webapp.name}"/>
+            <property name="waitfor.url" value="${webapp.waitfor.url}"/>
             <property name="testRecorder.config.name" 
value="${testRecorder.config.name}"/>
             <property name="suite.name" value="test"/>
+            <property name="playback.webapps" value="testRecorder"/>
             <property name="drt.mode" value="true"/>
         </ant>
     </target>
Index: trunk/netui/test/webapps/jsf/build.xml
===================================================================
--- trunk/netui/test/webapps/jsf/build.xml      (revision 36180)
+++ trunk/netui/test/webapps/jsf/build.xml      (working copy)
@@ -21,6 +21,7 @@
 
     <property name="webapp.name" value="jsfWeb"/>
     <property name="testRecorder.config.name" value="netui-server-jsf-config"/>
+    <property name="webapp.waitfor.url" 
value="http://localhost:8080/${webapp.name}"/>
 
     <!-- ================================================================ -->
     <!--                                                                  -->
@@ -64,15 +65,18 @@
         <ant antfile="${test.dir}/ant/testRecorder.xml" 
target="suite.callback" inheritAll="false">
             <property name="testRecorder.config.name" 
value="${testRecorder.config.name}"/>
             <property name="suite.name" value="drt"/>
+            <property name="playback.webapps" value="jsfWeb"/>
+            <property name="waitfor.url" value="${webapp.waitfor.url}"/>
         </ant>
     </target>
 
     <target name="drt" description="Run the drt suite with full server start / 
stop support.">
         <ant antfile="${test.dir}/ant/testRecorder.xml" inheritAll="false" 
target="server.test">
             <property name="app.build.file" 
location="${app.dir}/jsf/build.xml"/>
-            <property name="waitfor.url" 
value="http://localhost:8080/${webapp.name}"/>
+            <property name="waitfor.url" value="${webapp.waitfor.url}"/>
             <property name="testRecorder.config.name" 
value="${testRecorder.config.name}"/>
             <property name="suite.name" value="drt"/>
+            <property name="playback.webapps" value="jsfWeb"/>
             <property name="drt.mode" value="true"/>
         </ant>
     </target>
Index: trunk/netui/test/webapps/drt/coreWeb/testRecorder/startRecord.jsp
===================================================================
--- trunk/netui/test/webapps/drt/coreWeb/testRecorder/startRecord.jsp   
(revision 36180)
+++ trunk/netui/test/webapps/drt/coreWeb/testRecorder/startRecord.jsp   
(working copy)
@@ -31,8 +31,7 @@
 
   <tr>
     <td align="right"><strong>Test Name: </strong></td>
-    <td align="left"><input name="testName" type="text" size="30" />
-    <i style="color: blue" >or choose from the list of existing tests 
below.</i></td>
+    <td align="left"><input name="testName" type="text" size="30" /></td>
   </tr>
 
   <tr>
Index: trunk/netui/test/webapps/drt/coreWeb/testRecorder/test.jsp
===================================================================
--- trunk/netui/test/webapps/drt/coreWeb/testRecorder/test.jsp  (revision 36180)
+++ trunk/netui/test/webapps/drt/coreWeb/testRecorder/test.jsp  (working copy)
@@ -125,6 +125,32 @@
 <br>
 
 <a href="<%= contextPath 
%>/testRecorder?mode=playback&cmd=stop&testRecorder.filter.skip=true">playback 
STOP, no testId</a>
+<br>
+
+<a href="<%= contextPath 
%>/testRecorder?mode=xml&cmd=xml&file=unknown">unknown XML file</a>
+<br>
+
+<a href="<%= contextPath %>/testRecorder?mode=xml&cmd=xml&file=config">config 
XML file</a>
+<br>
+
+<a href="<%= contextPath %>/testRecorder?mode=xml&cmd=xml&file=webapp">webapp 
XML file</a>
+<br>
+
+<a href="<%= contextPath %>/testRecorder?mode=xml&cmd=xml&file=tests">tests 
XML file</a>
+<br>
+
+<a href="<%= contextPath 
%>/testRecorder?mode=xml&cmd=html&file=unknown">unknown HTML file</a>
+<br>
+
+<a href="<%= contextPath %>/testRecorder?mode=xml&cmd=html&file=config">config 
HTML file</a>
+<br>
+
+<a href="<%= contextPath %>/testRecorder?mode=xml&cmd=html&file=webapp">webapp 
HTML file</a>
+<br>
+
+<a href="<%= contextPath %>/testRecorder?mode=xml&cmd=html&file=tests">tests 
HTML file</a>
+<br>
+
 </body>
 
 </html>
Index: trunk/netui/test/webapps/drt/build.xml
===================================================================
--- trunk/netui/test/webapps/drt/build.xml      (revision 36180)
+++ trunk/netui/test/webapps/drt/build.xml      (working copy)
@@ -99,6 +99,7 @@
         <ant antfile="${test.dir}/ant/testRecorder.xml" 
target="suite.callback" inheritAll="false">
             <property name="testRecorder.config.name" 
value="${testRecorder.config.name}"/>
             <property name="suite.name" value="drt"/>
+            <property name="playback.webapps" value="coreWeb"/>
             <property name="waitfor.url" value="${webapp.waitfor.url}"/>
         </ant>
     </target>
@@ -107,16 +108,18 @@
         <ant antfile="${test.dir}/ant/testRecorder.xml" 
target="suite.callback" inheritAll="false">
             <property name="testRecorder.config.name" 
value="${testRecorder.config.name}"/>
             <property name="suite.name" value="bvt"/>
-            <property name="waitfor.url" value="http://localhost:8080/"/>
+            <property name="playback.webapps" value="coreWeb"/>
+            <property name="waitfor.url" value="${webapp.waitfor.url}"/>
         </ant>
     </target>
 
     <target name="drt" description="Run the drt suite with full server start / 
stop support.">
         <ant dir="${test.dir}" antfile="${test.dir}/ant/testRecorder.xml" 
inheritAll="false" target="server.test">
             <property name="app.build.file" 
location="${app.dir}/drt/build.xml"/>
-            <property name="waitfor.url" value="http://localhost:8080/"/>
+            <property name="waitfor.url" value="${webapp.waitfor.url}"/>
             <property name="testRecorder.config.name" 
value="${testRecorder.config.name}"/>
             <property name="suite.name" value="drt"/>
+            <property name="playback.webapps" value="coreWeb"/>
             <property name="drt.mode" value="true"/>
         </ant>
     </target>
@@ -124,9 +127,10 @@
     <target name="bvt" description="Run the bvt suite with full server start / 
stop support.">
         <ant antfile="${test.dir}/ant/testRecorder.xml" inheritAll="false" 
target="server.test">
             <property name="app.build.file" 
location="${app.dir}/drt/build.xml"/>
-            <property name="waitfor.url" value="http://localhost:8080/"/>
+            <property name="waitfor.url" value="${webapp.waitfor.url}"/>
             <property name="testRecorder.config.name" 
value="${testRecorder.config.name}"/>
             <property name="suite.name" value="bvt"/>
+            <property name="playback.webapps" value="coreWeb"/>
             <property name="drt.mode" value="true"/>
         </ant>
     </target>
Index: trunk/netui/test/ant/testRecorder.xml
===================================================================
--- trunk/netui/test/ant/testRecorder.xml       (revision 36180)
+++ trunk/netui/test/ant/testRecorder.xml       (working copy)
@@ -41,10 +41,10 @@
             </and>
         </condition>
         <condition property="formatter.type" value="xml">
-            <not><isset property="${drt.mode}"/></not>
+            <not><isset property="${formatter.type}"/></not>
         </condition>
         <condition property="formatter.usefile" value="true">
-            <not><isset property="${drt.mode}"/></not>
+            <not><isset property="${formatter.usefile}"/></not>
         </condition>
 
         <echo>formatter.type: ${formatter.type}</echo>
@@ -150,9 +150,10 @@
             </not>
         </condition>
         <fail if="_playback.fail">
-ERROR: to run playback set any combination of the following properties:
-    'playback.list', 'playback.categories', 'playback.webapps'
-    to a list of tests, categories or webapps, respectively
+ERROR: to run playback set playback.webapps to a list of webapps to test 
against or 'all' for all webapps and
+set some combination of the following: 'playback.list', 'playback.categories' 
to a list of tests,
+or categories, respectively.  The keyword 'all' can be used for 
'playback.categories' to include tests for
+all categories.
         </fail>
 
         <!-- remove old junit output -->
@@ -193,22 +194,18 @@
                 <isset property="playback.categories"/>
             </and>
         </condition>
-        <condition property="_webapps" value="">
-            <not>
-                <isset property="playback.webapps"/>
-            </not>
+        <condition property="_results.delete" value="true">
+            <or>
+                <istrue value="${drt.mode}"/>
+                <istrue value="${drt.cc.mode}"/>
+            </or>
         </condition>
-        <condition property="_webapps" value="${playback.webapps}">
-            <and>
-                <isset property="playback.webapps"/>
-            </and>
-        </condition>
 
         <echo>config.jar: ${_config.jar}</echo>
         <echo>log4j.config: ${log4j.config}</echo>
         <echo>playback list: ${_list}</echo>
         <echo>playback categories: ${_categories}</echo>
-        <echo>playback webapps: ${_webapps}</echo>
+        <echo>playback webapps: ${playback.webapps}</echo>
         <echo>playback config jar: ${_config.jar}</echo>
         <echo>test.recorder.classpath: ${test.recorder.classpath}</echo>
 
@@ -218,13 +215,13 @@
                 <pathelement path="${junit.jar}"/>
                 <pathelement path="${ant-junit.jar}"/>
                 <pathelement path="${test.recorder.classpath}"/>
-                <pathelement path="${_config.jar}"/>
+                <pathelement path="${test.dir}/conf"/>
             </classpath>
 
             <sysproperty key="test.recorder.run.tests" value="${_list}"/>
             <sysproperty key="test.recorder.run.categories" 
value="${_categories}"/>
-            <sysproperty key="test.recorder.run.webapps" value="${_webapps}"/>
-            <sysproperty key="test.recorder.run.results.delete" value="true"/>
+            <sysproperty key="test.recorder.run.webapps" 
value="${playback.webapps}"/>
+            <sysproperty key="test.recorder.run.results.delete" 
value="${results.delete}"/>
             <sysproperty key="netuidrt.logdir" 
path="${build.dir}/testRecorder"/>
             <sysproperty key="log4j.configuration" 
value="file:${log4j.config}"/>
 
@@ -244,14 +241,16 @@
                 <isset property="playback.drt.failure"/>
             </or>
         </condition>
+        <echo>drt.errors.found: ${drt.errors.found}</echo>
 
         <!-- Determine if we had a failure and are in DRT mode -->
         <condition property="drt.errors.stop">
             <and>
-                <isset property="drt.mode"/>
+                <isset property="drt.cc.mode"/>
                 <isset property="drt.errors.found"/>
             </and>
         </condition>
+        <echo>drt.errors.stop: ${drt.errors.stop}</echo>
 
         <!-- Run the DRT stop if we failed in DRT mode -->
         <antcall target="drt.errors"/>
@@ -441,6 +440,7 @@
 
         <ant dir="${test.dir}/ant" antfile="${test.dir}/ant/testRecorder.xml" 
target="run.suite">
             <property name="playback.categories" value="${suite.name}"/>
+            <property name="playback.webapps" value="${playback.webapps}"/>
         </ant>
     </target>
 
Index: trunk/netui/test/conf/junitLogCfgVerbose.xml
===================================================================
--- trunk/netui/test/conf/junitLogCfgVerbose.xml        (revision 36180)
+++ trunk/netui/test/conf/junitLogCfgVerbose.xml        (working copy)
@@ -6,7 +6,7 @@
   <!--Netui logfile -->
   <appender name="NETUISYSLOGFILE" 
class="org.apache.log4j.RollingFileAppender">
     <param name="File" value="${netuidrt.logdir}/netui.log"/>
-    <param name="Append" value="false"/>
+    <param name="Append" value="true"/>
     <param name="MaxFileSize" value="500000KB"/>
     <layout class="org.apache.log4j.PatternLayout">
       <param name="ConversionPattern" value="%d{DATE} %-5p %-15c{1} [%x]: 
%m%n"/>
Index: trunk/netui/test/conf/testRecorder-server.xml
===================================================================
--- trunk/netui/test/conf/testRecorder-server.xml       (revision 0)
+++ trunk/netui/test/conf/testRecorder-server.xml       (revision 0)
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<serverDefinition 
xmlns="http://beehive.apache.org/netui/tools/testrecorder/2004/server";>
+    <name>beehiveNetui</name>
+    <hostname>localhost</hostname>
+    <port>8080</port>
+    <webapps>
+        <webapp>
+            <name>coreWeb</name>
+            <contextRoot>/coreWeb</contextRoot>
+            <servletURI>testRecorder</servletURI>
+        </webapp>
+        <webapp>
+            <name>testRecorder</name>
+            <contextRoot>/testRecorder-test</contextRoot>
+            <servletURI>testRecorder</servletURI>
+        </webapp>
+        <webapp>
+            <name>jsfWeb</name>
+            <contextRoot>/jsfWeb</contextRoot>
+            <servletURI>testRecorder</servletURI>
+        </webapp>
+
+        <webapp>
+            <name>urlTemplates</name>
+            <contextRoot>/urlTemplates</contextRoot>
+            <servletURI>testRecorder</servletURI>
+        </webapp>
+        <!--
+        -->
+    </webapps>
+</serverDefinition>
\ No newline at end of file
Index: trunk/netui/test/src/testRecorder/schema/testRecorderServer.xsd
===================================================================
--- trunk/netui/test/src/testRecorder/schema/testRecorderServer.xsd     
(revision 0)
+++ trunk/netui/test/src/testRecorder/schema/testRecorderServer.xsd     
(revision 0)
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema";
+    xmlns="http://beehive.apache.org/netui/tools/testrecorder/2004/server";
+    
targetNamespace="http://beehive.apache.org/netui/tools/testrecorder/2004/server";
+    elementFormDefault="qualified">
+
+    <xs:element name="serverDefinition">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="name" type="nonZeroLengthString"/>
+                <xs:element name="hostname" type="nonZeroLengthString"/>
+                <xs:element name="port" type="xs:int"/>
+                <xs:element name="webapps" type="webappsDefType" 
minOccurs="1"/>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+
+    <xs:complexType name="webappsDefType">
+        <xs:sequence>
+            <xs:element name="webapp" type="webappDefType" minOccurs="1" 
maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="webappDefType">
+        <xs:sequence>
+            <xs:element name="name" type="nonZeroLengthString"/>
+            <xs:element name="description" type="xs:string" minOccurs="0"/>
+            <xs:element name="contextRoot" type="nonZeroLengthString"/>
+            <xs:element name="servletURI" type="nonZeroLengthString" 
minOccurs="1"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:simpleType name="nonZeroLengthString">
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+</xs:schema>
\ No newline at end of file
Index: 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/Constants.java
===================================================================
--- 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/Constants.java
 (revision 36180)
+++ 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/Constants.java
 (working copy)
@@ -30,7 +30,12 @@
     public static String CONFIG_FILE = "testRecorder-config.xml";
     public static String TESTS_FILE = "testRecorder-tests.xml";
     public static String WEBAPPS_FILE = "testRecorder-webapp.xml";
+    public static String SERVER_FILE = "testRecorder-server.xml";
 
+    public static String FILE_TYPE_CONFIG = "config";
+    public static String FILE_TYPE_WEBAPP = "webapp";
+    public static String FILE_TYPE_TESTS = "tests";
+
     // playback test number
     public static final String TEST_NUMBER_HEADER = 
"testRecorder.playback.testNumber";
     // playback session id.
@@ -88,6 +93,7 @@
     // 'mode' values
     public static final String RECORD = "record";
     public static final String PLAYBACK = "playback";
+    public static final String XML_MODE = "xml";
     public static final String ADMIN = "admin";
     public static final String CLEAN = "clean";
     public static final String SET_TEST_MODE_FALSE = "setTestModeFalse";
Index: 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/config/ServerDefinition.java
===================================================================
--- 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/config/ServerDefinition.java
   (revision 0)
+++ 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/config/ServerDefinition.java
   (revision 0)
@@ -0,0 +1,119 @@
+/*
+ * B E A   S Y S T E M S
+ * Copyright 2002-2004  BEA Systems, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+package org.apache.beehive.netui.tools.testrecorder.shared.config;
+
+import org.apache.beehive.netui.tools.testrecorder.shared.util.StringHelper;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * Client side object that defines server access info.
+ * <p/>
+ * User: ozzy
+ */
+public class ServerDefinition {
+
+    private String name;
+    private String hostname;
+    private int port;
+    private List webappList;
+    private Map webappMap;
+    private Map testDefMap;
+    private List testDefList;
+
+    public ServerDefinition( String name, String hostname, int port ) {
+        this.name = name;
+        this.hostname = hostname;
+        this.port = port;
+        webappList = new ArrayList();
+        webappMap = new HashMap();
+        testDefMap = new HashMap();
+        testDefList = new ArrayList();
+    }
+
+    public void addWebapp( WebappDefinition webapp ) {
+        webappList.add( webapp );
+        webappMap.put( webapp.getName(), webapp );
+    }
+
+    public WebappDefinition getWebapp( String webappName ) {
+        return (WebappDefinition) webappMap.get( webappName );
+    }
+
+    public WebappDefinition[] getWebapps() {
+        return (WebappDefinition[]) webappList.toArray( new 
WebappDefinition[webappList.size()] );
+    }
+
+    public int getWebappCount() {
+        return webappList.size();
+    }
+
+    public void addTestDefinitions( WebappDefinition webapp, TestDefinitions 
tests ) {
+        testDefMap.put( webapp, tests );
+        testDefList.add( tests );
+    }
+
+    public TestDefinitions getTestDefinitions( String webappName ) throws 
ConfigException {
+        WebappDefinition webapp = getWebapp( webappName );
+        if ( webapp == null ) {
+            throw new ConfigException( "No webapp exists for webapp with name( 
" + webappName );
+        }
+        return getTestDefinitions( webapp );
+    }
+
+    public TestDefinitions getTestDefinitions( WebappDefinition webapp ) {
+        return (TestDefinitions) testDefMap.get( webapp );
+    }
+
+    public TestDefinitions[] getTestDefinitions() {
+        return (TestDefinitions[]) testDefList.toArray( new 
TestDefinitions[testDefList.size()] );
+    }
+
+    public int getTestDefinitionsCount() {
+        return testDefList.size();
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getHostname() {
+        return hostname;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public String toString() {
+        StringBuffer sb = new StringBuffer( 48 );
+        sb.append( "[ " );
+        sb.append( "name( " + getName() + " )" );
+        sb.append( ", hostname( " + getHostname() + " )" );
+        sb.append( ", port( " + getPort() + " )" );
+        sb.append( ", webappList( " + StringHelper.toString( webappList, "\n", 
"\n\t" ) + " )" );
+        sb.append( " ]" );
+        return sb.toString();
+    }
+
+}

Property changes on: 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/config/ServerDefinition.java
___________________________________________________________________
Name: svn:eol-style
   + native

Index: 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/config/Webapps.java
===================================================================
--- 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/config/Webapps.java
    (revision 36180)
+++ 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/config/Webapps.java
    (working copy)
@@ -35,7 +35,7 @@
 
     // List of WebappConfig objects
     private List webappList;
-    // name -> Webapp
+    // name -> WebappConfig
     private Map webappNameMap;
 
     public Webapps( List webappList ) {
Index: 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/config/WebappDefinition.java
===================================================================
--- 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/config/WebappDefinition.java
   (revision 0)
+++ 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/config/WebappDefinition.java
   (revision 0)
@@ -0,0 +1,75 @@
+/*
+ * B E A   S Y S T E M S
+ * Copyright 2002-2004  BEA Systems, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+package org.apache.beehive.netui.tools.testrecorder.shared.config;
+
+import org.apache.beehive.netui.tools.testrecorder.shared.util.StringHelper;
+import org.apache.beehive.netui.tools.testrecorder.shared.Logger;
+
+import java.io.File;
+
+/**
+ * Client side object defining webapp access.
+ * User: ozzy
+ */
+public class WebappDefinition {
+
+    private static final Logger log = Logger.getInstance( 
WebappDefinition.class );
+
+    private String name;
+    private String description;
+    // includes leading slash
+    private String contextRoot;
+    private String servletUri;
+
+    public WebappDefinition( String name, String description, String 
contextRoot, String servletUri) {
+        this.name = name;
+        this.description = description;
+        this.contextRoot = contextRoot;
+        this.servletUri = contextRoot + "/" + servletUri;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public String getContextRoot() {
+        return contextRoot;
+    }
+
+    public String getServletUri() {
+        return servletUri;
+    }
+
+    public String toString() {
+        StringBuffer sb = new StringBuffer( 256 );
+        sb.append( "[ " );
+        sb.append( "name( " + getName() + " )" );
+        sb.append( ", description( " + getDescription() + " )" );
+        sb.append( ", contextRoot( " + getContextRoot() + " )" );
+        sb.append( ", servletURI( " + getServletUri() + " )" );
+        sb.append( " ]" );
+        return sb.toString();
+    }
+
+}

Property changes on: 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/config/WebappDefinition.java
___________________________________________________________________
Name: svn:eol-style
   + native

Index: 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/xmlbeans/XMLHelper.java
===================================================================
--- 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/xmlbeans/XMLHelper.java
        (revision 36180)
+++ 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/shared/xmlbeans/XMLHelper.java
        (working copy)
@@ -22,6 +22,8 @@
 import org.apache.beehive.netui.tools.testrecorder.x2004.*;
 import org.apache.beehive.netui.tools.testrecorder.x2004.TestsType;
 import org.apache.beehive.netui.tools.testrecorder.x2004.TestType;
+import 
org.apache.beehive.netui.tools.testrecorder.x2004.server.ServerDefinitionDocument;
+import org.apache.beehive.netui.tools.testrecorder.x2004.server.WebappDefType;
 import 
org.apache.beehive.netui.tools.testrecorder.x2004.diffsession.RecorderDiffDocument;
 import 
org.apache.beehive.netui.tools.testrecorder.x2004.diffsession.TestDiffType;
 import org.apache.beehive.netui.tools.testrecorder.x2004.session.*;
@@ -52,6 +54,68 @@
 
     private static final Logger log = Logger.getInstance( XMLHelper.class );
 
+    public static ServerDefinition getServerDefinition( File file ) throws 
ConfigException, IOException {
+        if ( log.isInfoEnabled() ) {
+            log.info( "file( " + file.getAbsolutePath() + " )" );
+        }
+        InputStream is = new FileInputStream( file );
+        return getServerDefinition( is, file.getAbsolutePath() );
+    }
+
+    public static ServerDefinition getServerDefinition( InputStream is, String 
resourceIdentifier )
+            throws ConfigException, IOException {
+        ServerDefinitionDocument doc = null;
+        try {
+            XmlOptions loadOptions = new XmlOptions();
+            loadOptions.setLoadLineNumbers();
+            doc = ServerDefinitionDocument.Factory.parse( is, loadOptions );
+        }
+        catch ( XmlException e ) {
+            log.fatal( "test recorder parse exception", e );
+            ConfigException ex = new ConfigException( "ERROR: failed parsing 
test recorder server definition XML, file( " +
+                    resourceIdentifier + " )", e );
+            log.fatal( ex );
+            throw ex;
+        }
+        finally {
+            if ( is != null ) {
+                try {
+                    is.close();
+                }
+                catch ( IOException e ) {
+                    log.error( "ERROR: failed to close stream for file( " + 
resourceIdentifier + " )" );
+                }
+            }
+        }
+
+        assert doc != null;
+        try {
+            validate( doc, resourceIdentifier,
+                    "ERROR: test recorder server definition XML document is 
not valid against the schema" );
+        }
+        catch ( ConfigException e ) {
+            log.fatal( "test recorder failed validating server definition 
file( " + resourceIdentifier + " )", e );
+            throw e;
+        }
+        ServerDefinition server = new ServerDefinition( 
doc.getServerDefinition().getName(),
+                doc.getServerDefinition().getHostname(), 
doc.getServerDefinition().getPort() );
+        populateServerDefinition( server, doc );
+        return server;
+    }
+
+    public static void populateServerDefinition( final ServerDefinition 
server, final ServerDefinitionDocument doc ) {
+        int cnt = doc.getServerDefinition().getWebapps().sizeOfWebappArray();
+        WebappDefType webappType = null;
+        WebappDefinition webapp = null;
+        for ( int i = 0; i < cnt; i++ ) {
+            webappType = 
doc.getServerDefinition().getWebapps().getWebappArray( i );
+            webapp = new WebappDefinition( webappType.getName(), 
webappType.getDescription(),
+                    webappType.getContextRoot(), webappType.getServletURI() );
+            server.addWebapp( webapp );
+        }
+        return;
+    }
+
     public static RecordSessionBean getRecordSessionBean( File file ) throws 
SessionXMLException, IOException {
         if ( log.isInfoEnabled() ) {
             log.info( "file( " + file.getAbsolutePath() + " )" );
@@ -645,7 +709,7 @@
         }
         catch ( IOException e ) {
             log.fatal( "ERROR: encountered IOException processing resource( " 
+ Constants.TESTS_FILE + " )", e );
-            throw new RuntimeException( "ERROR: encountered IOException 
processing resource( " +
+            throw new RuntimeConfigException( "ERROR: encountered IOException 
processing resource( " +
                     Constants.TESTS_FILE + " ), message( " + e.getMessage(), e 
);
         }
         finally {
Index: 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/server/TestRecorderServlet.java
===================================================================
--- 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/server/TestRecorderServlet.java
       (revision 36180)
+++ 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/server/TestRecorderServlet.java
       (working copy)
@@ -23,6 +23,8 @@
 import java.io.IOException;
 import java.io.Writer;
 import java.io.FileReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -100,6 +102,9 @@
             else if ( mode.equalsIgnoreCase( Constants.ADMIN ) ) {
                 doAdmin( request, response );
             }
+            else if ( mode.equalsIgnoreCase( Constants.XML_MODE ) ) {
+                doXml( request, response );
+            }
             else {
                 // fail
                 String msg = "unknown mode( " + mode + " ).";
@@ -782,6 +787,102 @@
         }
     }
 
+    private void doXml( HttpServletRequest request, HttpServletResponse 
response ) throws ServletException,
+            IOException {
+        String outputType = request.getParameter( Constants.CMD );
+        boolean outputHtml = false;
+        if ( outputType.equalsIgnoreCase( "xml" ) ) {
+            outputHtml = false;
+        }
+        else if ( outputType.equalsIgnoreCase( "html" ) ) {
+            outputHtml = true;
+        }
+        else {
+            // fail
+            String msg = "ERROR: unable to handle Xml request: '" + 
Constants.CMD + "' ( " + outputType +
+                    " ) is not recognized.";
+            forward( request, response, msg, Constants.ERROR_PAGE, true );
+            return;
+        }
+        String fileType = request.getParameter( Constants.FILE );
+        String resource = null;
+        if ( fileType.equalsIgnoreCase( Constants.FILE_TYPE_CONFIG ) ) {
+            resource = Constants.CONFIG_FILE;
+        }
+        else if ( fileType.equalsIgnoreCase( Constants.FILE_TYPE_WEBAPP ) ) {
+            resource = Constants.WEBAPPS_FILE;
+        }
+        else if ( fileType.equalsIgnoreCase( Constants.FILE_TYPE_TESTS ) ) {
+            resource = Constants.TESTS_FILE;
+        }
+        else {
+            // fail
+            String msg = "ERROR: unable to handle Xml request: '" + 
Constants.FILE + "' ( " + fileType +
+                    " ) is not recognized.";
+            forward( request, response, msg, Constants.ERROR_PAGE, true );
+            return;
+        }
+
+        InputStream is = 
Thread.currentThread().getContextClassLoader().getResourceAsStream( resource );
+        if ( is == null ) {
+            // fail
+            String msg = "ERROR: unable to handle Xml request, unable to 
obtain stream for resource( " +
+                    resource + " )";
+            forward( request, response, msg, Constants.ERROR_PAGE, true );
+            return;
+        }
+        if ( outputHtml ) {
+            response.setContentType( "text/html" );
+        }
+        else {
+            response.setContentType( "text/xml" );
+        }
+        doResourceStream( request, response, is, resource, outputHtml );
+    }
+
+    private void doResourceStream( HttpServletRequest request, 
HttpServletResponse response, final InputStream is,
+            final String resource, final boolean outputHtml ) throws 
ServletException, IOException {
+        InputStreamReader reader = null;
+        Writer wrtr = null;
+        try {
+            wrtr = response.getWriter();
+            if ( outputHtml ) {
+                wrtr.write( "<html><title>" + Reporter.escape( resource ) + 
"</title><body><b>" + resource +
+                        "</b><br /><br /><pre>" );
+            }
+            // output an html page
+            char[] buf = new char[1024];
+            reader = new InputStreamReader( is );
+            int size;
+            while ( true ) {
+                size = reader.read( buf, 0, 1024 );
+                if ( size == -1 ) {
+                    break;
+                }
+                if ( outputHtml ) {
+                    wrtr.write( Reporter.escape( buf, size ) );
+                }
+                else {
+                    wrtr.write( buf, 0, size );
+                }
+            }
+        }
+        catch ( Exception e ) {
+            String msg = "ERROR: failed to write resource( " + resource + " ) 
as stream , exception( " +
+                    e.getMessage() +
+                    " )";
+            forward( request, response, msg, Constants.ERROR_PAGE, true, e );
+        }
+        finally {
+            if ( outputHtml && wrtr != null ) {
+                wrtr.write( "</pre></body></html>" );
+            }
+            if ( reader != null ) {
+                reader.close();
+            }
+        }
+    }
+
     private static String getTestName( HttpServletRequest request ) {
         return request.getParameter( Constants.TEST_NAME );
     }
Index: 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/client/TestRecorderJUnitTest.java
===================================================================
--- 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/client/TestRecorderJUnitTest.java
     (revision 36180)
+++ 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/client/TestRecorderJUnitTest.java
     (working copy)
@@ -33,10 +33,15 @@
     private TestDefinition test;
 
     public TestRecorderJUnitTest( TestDefinition test ) {
-        super( test.getName() );
+        this( test, test.getName() );
         this.test = test;
     }
 
+    public TestRecorderJUnitTest( TestDefinition test, String name ) {
+        super( name );
+        this.test = test;
+    }
+
     protected void runTest() throws Throwable {
         boolean outcome = execute();
         if ( !outcome ) {
Index: 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/client/PlaybackExecutor.java
===================================================================
--- 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/client/PlaybackExecutor.java
  (revision 36180)
+++ 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/client/PlaybackExecutor.java
  (working copy)
@@ -51,6 +51,9 @@
 
     private static final Logger log = Logger.getInstance( 
PlaybackExecutor.class );
 
+    private static HttpClient controlClient = new HttpClient();
+    private static HttpClient testClient = new HttpClient();
+
     private static final DecimalFormat format = (DecimalFormat)
             NumberFormat.getInstance( Locale.US );
 
@@ -67,11 +70,9 @@
     private File resultsFile;
     private File diffFile;
 
-    private HttpClient controlClient;
     private NameValuePair[] startParams;
     private NameValuePair[] stopParams;
 
-    private HttpClient testClient;
     private String testId;
     private RecordSessionBean session;
 
@@ -85,8 +86,6 @@
             description = "No Description.";
         }
         this.testUser = testUser;
-        this.testClient = new HttpClient();
-        this.controlClient = new HttpClient();
         setControlParams();
     }
 
Index: 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/client/MasterTestRecorderJUnitTest.java
===================================================================
--- 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/client/MasterTestRecorderJUnitTest.java
       (revision 36180)
+++ 
trunk/netui/test/src/testRecorder/org/apache/beehive/netui/tools/testrecorder/client/MasterTestRecorderJUnitTest.java
       (working copy)
@@ -23,11 +23,22 @@
 import junit.framework.Test;
 import junit.framework.TestCase;
 import org.apache.beehive.netui.tools.testrecorder.shared.Logger;
+import org.apache.beehive.netui.tools.testrecorder.shared.Constants;
 import org.apache.beehive.netui.tools.testrecorder.shared.xmlbeans.XMLHelper;
 import 
org.apache.beehive.netui.tools.testrecorder.shared.config.TestDefinitions;
 import 
org.apache.beehive.netui.tools.testrecorder.shared.config.TestDefinition;
 import 
org.apache.beehive.netui.tools.testrecorder.shared.config.RuntimeConfigException;
 import org.apache.beehive.netui.tools.testrecorder.shared.config.WebappConfig;
+import 
org.apache.beehive.netui.tools.testrecorder.shared.config.ServerDefinition;
+import 
org.apache.beehive.netui.tools.testrecorder.shared.config.WebappDefinition;
+import 
org.apache.beehive.netui.tools.testrecorder.shared.config.ConfigException;
+import org.apache.beehive.netui.tools.testrecorder.shared.config.Config;
+import org.apache.beehive.netui.tools.testrecorder.shared.config.Webapps;
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpRecoverableException;
+import org.apache.commons.httpclient.methods.GetMethod;
 
 import java.util.List;
 import java.util.ArrayList;
@@ -35,57 +46,79 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Iterator;
+import java.io.InputStream;
+import java.io.IOException;
 
+
 /**
  */
 public class MasterTestRecorderJUnitTest extends TestCase {
 
     private static final Logger log = Logger.getInstance( 
MasterTestRecorderJUnitTest.class );
-    private static TestDefinitions testDefinitions;
-
     // specified when invoking the test to describe the tests to run
-    public static String TESTS_PROPERTY = "test.recorder.run.tests";
-    public static String CATEGORIES_PROPERTY = "test.recorder.run.categories";
-    public static String WEBAPPS_PROPERTY = "test.recorder.run.webapps";
-    public static String ALL_PROPERTY = "test.recorder.run.all";
-    public static String DELETE_RESULTS_PROPERTY = 
"test.recorder.run.results.delete";
+    public static final String TESTS_PROPERTY = "test.recorder.run.tests";
+    public static final String CATEGORIES_PROPERTY = 
"test.recorder.run.categories";
+    public static final String WEBAPPS_PROPERTY = "test.recorder.run.webapps";
+    public static final String DELETE_RESULTS_PROPERTY = 
"test.recorder.run.results.delete";
+    private static final NameValuePair configParam = new NameValuePair( 
Constants.FILE,
+            Constants.FILE_TYPE_CONFIG );
+    private static final NameValuePair webappParam = new NameValuePair( 
Constants.FILE,
+            Constants.FILE_TYPE_WEBAPP );
+    private static final NameValuePair testsParam = new NameValuePair( 
Constants.FILE, Constants.FILE_TYPE_TESTS );
 
+    private static ServerDefinition serverDef;
+    private static NameValuePair[] queryParams = new NameValuePair[3];
 
+    static {
+        queryParams[0] = new NameValuePair( Constants.MODE, "xml" );
+        queryParams[1] = new NameValuePair( Constants.CMD, "xml" );
+    }
+
+    private static HttpClient controlClient = new HttpClient();
+
     public MasterTestRecorderJUnitTest() {
         super( "MasterTestRecorderJUnitTest" );
     }
 
     public static Test suite() {
-        initialize();
         TestSuite suite = null;
-        suite = new TestSuite();
-        buildSuite( suite );
+        try {
+            initialize();
+            suite = new TestSuite();
+            buildSuite( suite );
+        }
+        catch ( Throwable e ) {
+            String msg = "Failed building test recorder junit suite, 
exception( " + e.getMessage() + " )";
+            log.error( msg, e );
+            if ( e instanceof RuntimeException ) {
+                throw (RuntimeException) e;
+            }
+            throw new RuntimeException( msg, e );
+        }
         return suite;
     }
 
     private static void buildSuite( TestSuite suite ) {
         boolean delete = getDeleteResultsProperty();
         HashMap webappMap = new HashMap();
-        if ( getAllProperty() ) {
-            List list = getTestDefinitions().getTestDefinitions();
-            addList( list, suite, webappMap );
+        TestDefinitions testDefs = null;
+        TestDefinitions[] testDefList = serverDef.getTestDefinitions();
+        boolean includeWebappInName = ( testDefList.length > 1 ) ? true : 
false;
+        for ( int i = 0; i < testDefList.length; i++ ) {
+            testDefs = (TestDefinitions) testDefList[i];
+            List list = getTestList( getTestsProperty(), testDefs );
+            addList( list, suite, webappMap, includeWebappInName );
+            list = getTestsByCategory( getCategoriesProperty(), testDefs );
+            addList( list, suite, webappMap, includeWebappInName );
         }
-        else {
-            List list = getTestList( getTestsProperty() );
-            addList( list, suite, webappMap );
-            list = getTestsByCategory( getCategoriesProperty() );
-            addList( list, suite, webappMap );
-            list = getTestsByWebapp( getWebappsProperty() );
-            addList( list, suite, webappMap );
-        }
         if ( log.isInfoEnabled() ) {
             log.info( "Test recorder test suite consists of (" + 
suite.countTestCases() + ") tests" );
         }
         if ( suite.countTestCases() == 0 ) {
-            String msg = "ERROR: no tests specified";
+            String msg = "ERROR: no tests specified, check for warning of 
skipped webapps, tests and categories";
             System.err.println( msg );
             log.fatal( msg );
-            throw new RuntimeConfigException( "ERROR: no tests specified" );
+            throw new RuntimeConfigException( msg );
         }
         // Delete results file for all webapps used, create results directory 
if it doesn't exist
         // TODO move to server to allow for playback from remote server
@@ -113,28 +146,294 @@
         }
     }
 
-    private static void addList( List list, TestSuite suite, HashMap webappMap 
) {
+    private static void addList( List list, TestSuite suite, HashMap 
webappMap, boolean includeWebappInName ) {
         TestDefinition def = null;
         for ( int i = 0; i < list.size(); i++ ) {
             def = (TestDefinition) list.get( i );
             log.debug( "Adding test( " + def.getName() + " )to JUnit suite" );
-            suite.addTest( new TestRecorderJUnitTest( def ) );
+            if ( includeWebappInName ) {
+                suite.addTest( new TestRecorderJUnitTest( def, 
def.getWebapp().getName() ) );
+            }
+            else {
+                suite.addTest( new TestRecorderJUnitTest( def ) );
+            }
             addWebapp( webappMap, def.getWebapp() );
         }
     }
 
-    private static void initialize() {
-        testDefinitions = XMLHelper.getTestDefinitionsInstance( 
Thread.currentThread().getContextClassLoader() );
+    private static void initialize() throws ConfigException, IOException {
+        InputStream is = 
Thread.currentThread().getContextClassLoader().getResourceAsStream(
+                Constants.SERVER_FILE );
+        try {
+            serverDef = XMLHelper.getServerDefinition( is, 
Constants.SERVER_FILE );
+        }
+        catch ( Throwable e ) {
+            String msg = "Failed to obtain test recorder server definition 
from XML";
+            log.error( msg, e );
+            throw new ConfigException( msg, e );
+        }
+        finally {
+            if ( is != null ) {
+                try {
+                    is.close();
+                }
+                catch ( IOException e ) {
+                    log.error( "Failed closing stream of server definition 
XML", e );
+                    throw e;
+                }
+            }
+        }
+        if ( serverDef == null ) {
+            String msg = "Failed to obtain test recorder server definition 
from XML";
+            log.error( msg );
+            throw new ConfigException( msg );
+        }
+        // the schema insures that at least one webapp is defined
+        assert serverDef.getWebappCount() != 0 : "no webapps defined in server 
definition XML file" ;
+        String webappList = getWebappsProperty();
+        if ( webappList == null ) {
+            String msg = "ERROR: the '" + WEBAPPS_PROPERTY + "' property must 
be set.";
+            log.error( msg );
+            throw new ConfigException( msg );
+        }
+        webappList = webappList.trim();
+        WebappDefinition webapp = null;
+        TestDefinitions tests = null;
+        if ( webappList.equalsIgnoreCase( "all" ) ) {
+            WebappDefinition[] webappDefList = serverDef.getWebapps();
+            for ( int i = 0; i < webappDefList.length; i++ ) {
+                webapp = webappDefList[i];
+                tests = getTestDefinitions( webapp );
+                if ( tests == null ) {
+                    continue;
+                }
+                serverDef.addTestDefinitions( webapp, tests );
+            }
+        }
+        else {
+            String webappName = null;
+            for ( StringTokenizer stringTokenizer = new StringTokenizer( 
webappList, "," );
+                    stringTokenizer.hasMoreTokens(); ) {
+                webappName = stringTokenizer.nextToken().trim();
+                if ( webappName.length() == 0 ) {
+                    continue;
+                }
+                webapp = serverDef.getWebapp( webappName );
+                if ( webapp == null ) {
+                    String msg = "WARNING: no webapp found with name( " + 
webappName + " )";
+                    if ( log.isWarnEnabled() ) {
+                        log.warn( msg );
+                    }
+                    System.err.println( msg );
+                    continue;
+                }
+                if ( log.isDebugEnabled() ) {
+                    log.debug( "retrieving test definition for webapp at( " + 
webapp.getContextRoot() + " )" );
+                }
+                tests = getTestDefinitions( webapp );
+                if ( tests == null ) {
+                    continue;
+                }
+                serverDef.addTestDefinitions( webapp, tests );
+            }
+        }
+        if ( serverDef.getTestDefinitionsCount() == 0 ) {
+            String msg = "ERROR: no test definitions found";
+            log.error( msg );
+            throw new ConfigException( msg );
+        }
     }
 
-    private static TestDefinitions getTestDefinitions() {
+    private static TestDefinitions getTestDefinitions( WebappDefinition webapp 
) {
+        TestDefinitions tests = null;
+        try {
+            tests = retrieveTestDefinitions( serverDef, webapp );
+        }
+        catch ( ConfigException e ) {
+            String msg = "WARNING: failed to obtain test definitions for 
webapp at( " +
+                    webapp.getContextRoot() + " )";
+            if ( log.isWarnEnabled() ) {
+                log.warn( msg, e );
+            }
+            System.err.println( msg );
+        }
+        return tests;
+    }
+
+    private static TestDefinitions retrieveTestDefinitions( ServerDefinition 
server, WebappDefinition webapp )
+            throws ConfigException {
+        String uri = genUri( "http", server.getHostname(), server.getPort(), 
webapp.getServletUri() );
+        HttpMethod method = new GetMethod( uri );
+        queryParams[2] = configParam;
+        method.setQueryString( queryParams );
+        InputStream is = executeXMLRequest( method, uri, Constants.CONFIG_FILE 
);
+        Config config = null;
+        try {
+            config = XMLHelper.getConfig( is, Constants.CONFIG_FILE );
+        }
+        catch ( Exception e ) {
+            String msg = "ERROR: encountered exception processing resource( " 
+ Constants.CONFIG_FILE + " )";
+            log.fatal( msg, e );
+            if ( e instanceof ConfigException ) {
+                throw (ConfigException) e;
+            }
+            throw new ConfigException( msg, e );
+        }
+        finally {
+            try {
+                if ( is != null ) {
+                    is.close();
+                }
+            }
+            catch ( IOException e ) {
+                if ( log.isWarnEnabled() ) {
+                    log.warn( "WARNING: received exception closing HTTP stream 
for( " + Constants.CONFIG_FILE +
+                            " )", e );
+                }
+                //ignore
+            }
+            method.releaseConnection();
+        }
+        if ( log.isInfoEnabled() ) {
+            log.info( "config( " + config + " )" );
+        }
+
+        method = new GetMethod( uri );
+        queryParams[2] = webappParam;
+        method.setQueryString( queryParams );
+        is = executeXMLRequest( method, uri, Constants.WEBAPPS_FILE );
+        Webapps webapps = null;
+        try {
+            webapps = XMLHelper.getWebapps( is, Constants.WEBAPPS_FILE, config 
);
+        }
+        catch ( Exception e ) {
+            String msg = "ERROR: encountered exception processing resource( " 
+ Constants.WEBAPPS_FILE + " )";
+            log.fatal( msg, e );
+            if ( e instanceof ConfigException ) {
+                throw (ConfigException) e;
+            }
+            throw new ConfigException( msg, e );
+        }
+        finally {
+            try {
+                if ( is != null ) {
+                    is.close();
+                }
+            }
+            catch ( IOException e ) {
+                if ( log.isWarnEnabled() ) {
+                    log.warn( "WARNING: received exception closing HTTP stream 
for( " + Constants.WEBAPPS_FILE +
+                            " )", e );
+                }
+                // ignore
+            }
+            method.releaseConnection();
+        }
+        if ( log.isInfoEnabled() ) {
+            log.info( "webapps( " + webapps + " )" );
+        }
+
+        method = new GetMethod( uri );
+        queryParams[2] = testsParam;
+        method.setQueryString( queryParams );
+        is = executeXMLRequest( method, uri, Constants.TESTS_FILE );
+        TestDefinitions testDefinitions = null;
+        try {
+            testDefinitions = XMLHelper.getTestDefinitionsInstance( is, 
Constants.TESTS_FILE, webapps,
+                    config.getBaseDirectory().getAbsolutePath() );
+        }
+        catch ( Exception e ) {
+            String msg = "ERROR: encountered exception processing resource( " 
+ Constants.TESTS_FILE + " )";
+            log.fatal( msg, e );
+            if ( e instanceof ConfigException ) {
+                throw (ConfigException) e;
+            }
+            throw new ConfigException( msg, e );
+        }
+        finally {
+            try {
+                if ( is != null ) {
+                    is.close();
+                }
+            }
+            catch ( IOException e ) {
+                if ( log.isWarnEnabled() ) {
+                    log.warn( "WARNING: received exception closing HTTP stream 
for( " + Constants.TESTS_FILE +
+                            " )", e );
+                }
+                // ignore
+            }
+            method.releaseConnection();
+        }
+        if ( log.isDebugEnabled() ) {
+//            log.debug( "testDefinitions( " + testDefinitions + " )" );
+        }
         return testDefinitions;
     }
 
+    private static InputStream executeXMLRequest( HttpMethod method, String 
uri, String resourceIdentifier )
+            throws ConfigException {
+        InputStream is = null;
+        try {
+            is = executeHttpRequest( controlClient, method );
+        }
+        catch ( Exception e ) {
+            String msg = "Failed to obtain '" + resourceIdentifier + "' from 
webapp at uri( " + uri + " )";
+            log.error( msg, e );
+            if ( is != null ) {
+                try {
+                    is.close();
+                }
+                catch ( IOException e1 ) {
+                    // ignore
+                }
+            }
+            method.releaseConnection();
+            throw new ConfigException( msg, e );
+        }
+        return is;
+    }
+
+    private static InputStream executeHttpRequest( HttpClient client, 
HttpMethod method ) throws ConfigException,
+            IOException {
+        int statusCode = -1;
+        // retry up to 3 times.
+        for ( int attempt = 0; statusCode == -1 && attempt < 3; attempt++ ) {
+            try {
+                statusCode = client.executeMethod( method );
+            }
+            catch ( HttpRecoverableException e ) {
+                if ( log.isWarnEnabled() ) {
+                    String msg = "A recoverable exception occurred calling 
URI( " + method.getURI() +
+                            " ), retrying. exception( " + e.getMessage() + " 
)";
+                    log.error( msg, e );
+                }
+            }
+            catch ( IOException e ) {
+                String msg = "Failed executing request( " + method.getURI() + 
" ), exception( " + e.getMessage() +
+                        " )";
+                log.error( msg, e );
+                throw e;
+            }
+        }
+        // Retries failed
+        if ( statusCode == -1 ) {
+            String msg = "Failed to execute request( " + method.getURI() + " 
)";
+            log.error( msg );
+            throw new ConfigException( msg );
+        }
+        InputStream is = method.getResponseBodyAsStream();
+        return is;
+    }
+
+    public static String genUri( String protocol, String host, int port, 
String path ) {
+        return protocol + "://" + host + ":" + port + path;
+    }
+
     /**
      * Returns a List of TestDefinition objects
      */
-    private static List getTestList( String testList ) {
+    private static List getTestList( String testList, TestDefinitions testDefs 
) {
         List list = new ArrayList();
         if ( testList == null ) {
             return list;
@@ -147,13 +446,14 @@
             if ( name.length() == 0 ) {
                 continue;
             }
-            test = getTestDefinitions().getTest( name );
+            test = testDefs.getTest( name );
             if ( test == null ) {
+                String msg = "WARNING: unable to find test with name( " + name 
+" ) in webapp( " +
+                testDefs.getWebapps().toString() + " ), skippping";
                 if ( log.isWarnEnabled() ) {
-                    String msg = "WARNING: unable to find test with name( " + 
name + " ), skipping test";
-                    System.err.println( msg );
                     log.warn( msg );
                 }
+                System.err.println( msg );
                 continue;
             }
             list.add( test );
@@ -161,7 +461,7 @@
         return list;
     }
 
-    private static List getTestsByCategory( String categoryList ) {
+    private static List getTestsByCategory( String categoryList, 
TestDefinitions testDefs ) {
         String category = null;
         List list = new ArrayList();
         if ( categoryList == null ) {
@@ -174,31 +474,21 @@
             if ( category.length() == 0 ) {
                 continue;
             }
-            temp = getTestDefinitions().getCategories().getTests( category );
-            if ( temp == null ) {
-                throw new RuntimeConfigException( "ERROR: unable to find 
category( " + category + " )" );
+            // implicit category
+            if ( category.equalsIgnoreCase( "all" ) ) {
+                temp = testDefs.getTestDefinitions();
             }
-            list.addAll( temp );
-        }
-        return list;
-    }
-
-    private static List getTestsByWebapp( String webappList ) {
-        String webapp = null;
-        List list = new ArrayList();
-        if ( webappList == null ) {
-            return list;
-        }
-        List temp = null;
-        for ( StringTokenizer stringTokenizer = new StringTokenizer( 
webappList, "," );
-                stringTokenizer.hasMoreTokens(); ) {
-            webapp = stringTokenizer.nextToken().trim();
-            if ( webapp.length() == 0 ) {
-                continue;
+            else {
+                temp = testDefs.getCategories().getTests( category );
             }
-            temp = getTestDefinitions().getTestList( webapp );
             if ( temp == null ) {
-                throw new RuntimeConfigException( "ERROR: no tests for webapp( 
" + webapp + " )" );
+                String msg = "WARNING: unable to find category( " + category + 
" ) in webapp( " +
+                testDefs.getWebapps().toString() + " ), skippping";
+                if ( log.isWarnEnabled() ) {
+                    log.warn( msg );
+                }
+                System.err.println( msg );
+                continue;
             }
             list.addAll( temp );
         }
@@ -206,7 +496,7 @@
     }
 
     private static boolean getDeleteResultsProperty() {
-        return Boolean.valueOf( getProperty( DELETE_RESULTS_PROPERTY ) 
).booleanValue(); 
+        return Boolean.valueOf( getProperty( DELETE_RESULTS_PROPERTY ) 
).booleanValue();
     }
 
     private static String getTestsProperty() {
@@ -221,9 +511,6 @@
         return getProperty( WEBAPPS_PROPERTY );
     }
 
-    private static boolean getAllProperty() {
-        return Boolean.valueOf( getProperty( ALL_PROPERTY ) ).booleanValue(); 
-    }
 
     private static String getProperty( String prop ) {
         String value = null;
@@ -244,4 +531,4 @@
             map.put( webapp.getName(), webapp );
         }
     }
-}
\ No newline at end of file
+}
Index: trunk/netui/test/src/testRecorder/jsp/startRecord.jsp
===================================================================
--- trunk/netui/test/src/testRecorder/jsp/startRecord.jsp       (revision 36180)
+++ trunk/netui/test/src/testRecorder/jsp/startRecord.jsp       (working copy)
@@ -31,8 +31,7 @@
 
   <tr>
     <td align="right"><strong>Test Name: </strong></td>
-    <td align="left"><input name="testName" type="text" size="30" />
-    <i style="color: blue" >or choose from the list of existing tests 
below.</i></td>
+    <td align="left"><input name="testName" type="text" size="30" /></td>
   </tr>
 
   <tr>
Index: trunk/netui/test/src/testRecorder/jsp/test.jsp
===================================================================
--- trunk/netui/test/src/testRecorder/jsp/test.jsp      (revision 36180)
+++ trunk/netui/test/src/testRecorder/jsp/test.jsp      (working copy)
@@ -125,6 +125,32 @@
 <br>
 
 <a href="<%= contextPath 
%>/testRecorder?mode=playback&cmd=stop&testRecorder.filter.skip=true">playback 
STOP, no testId</a>
+<br>
+
+<a href="<%= contextPath 
%>/testRecorder?mode=xml&cmd=xml&file=unknown">unknown XML file</a>
+<br>
+
+<a href="<%= contextPath %>/testRecorder?mode=xml&cmd=xml&file=config">config 
XML file</a>
+<br>
+
+<a href="<%= contextPath %>/testRecorder?mode=xml&cmd=xml&file=webapp">webapp 
XML file</a>
+<br>
+
+<a href="<%= contextPath %>/testRecorder?mode=xml&cmd=xml&file=tests">tests 
XML file</a>
+<br>
+
+<a href="<%= contextPath 
%>/testRecorder?mode=xml&cmd=html&file=unknown">unknown HTML file</a>
+<br>
+
+<a href="<%= contextPath %>/testRecorder?mode=xml&cmd=html&file=config">config 
HTML file</a>
+<br>
+
+<a href="<%= contextPath %>/testRecorder?mode=xml&cmd=html&file=webapp">webapp 
HTML file</a>
+<br>
+
+<a href="<%= contextPath %>/testRecorder?mode=xml&cmd=html&file=tests">tests 
HTML file</a>
+<br>
+
 </body>
 
 </html>
Index: trunk/netui/test/src/testRecorder/build.xml
===================================================================
--- trunk/netui/test/src/testRecorder/build.xml (revision 36180)
+++ trunk/netui/test/src/testRecorder/build.xml (working copy)
@@ -2,7 +2,7 @@
 
 <project name="Beehive/NetUI/testRecorder" default="compile" basedir=".">
 
-    <property name="module.classpath" 
location="${deployed.junit.jar};${deployed.httpClient.jar};${deployed.commons-logging.jar};${log4j.jar};${servlet24.jar};${jsp20.jar};${xbean.jar};${junit.jar}"/>
+    <property name="module.classpath" 
location=";${deployed.httpClient.jar};${deployed.commons-logging.jar};${log4j.jar};${servlet24.jar};${jsp20.jar};${xbean.jar};${junit.jar}"/>
     <property name="module.classes.dir" 
location="${qa.classes.dir}/${module.name}"/>
     <property name="module.jar.name" value="${test-recorder.jar.name}"/>
     <property name="module.jar" location="${qa.lib.dir}/${module.jar.name}"/>
@@ -26,6 +26,7 @@
                classpath="${module.classpath}"
                debug="${compile.debug}"
                deprecation="${compile.deprecation}"
+               source="${compile.source}"
                optimize="${compile.optimize}">
                <include name="**/*.java"/>
         </javac>
Index: 
trunk/netui/test/src/testRecorderQA/org/apache/beehive/netui/tools/testrecorder/qa/SchemaTest.java
===================================================================
--- 
trunk/netui/test/src/testRecorderQA/org/apache/beehive/netui/tools/testrecorder/qa/SchemaTest.java
  (revision 36180)
+++ 
trunk/netui/test/src/testRecorderQA/org/apache/beehive/netui/tools/testrecorder/qa/SchemaTest.java
  (working copy)
@@ -26,6 +26,7 @@
 import java.io.IOException;
 
 import org.apache.beehive.netui.tools.testrecorder.shared.Logger;
+import org.apache.beehive.netui.tools.testrecorder.shared.Constants;
 import org.apache.beehive.netui.tools.testrecorder.shared.xmlbeans.XMLHelper;
 import org.apache.beehive.netui.tools.testrecorder.shared.config.Config;
 import org.apache.beehive.netui.tools.testrecorder.shared.config.Webapps;
@@ -33,6 +34,7 @@
 import 
org.apache.beehive.netui.tools.testrecorder.shared.config.ConfigException;
 import org.apache.beehive.netui.tools.testrecorder.shared.config.WebappConfig;
 import org.apache.beehive.netui.tools.testrecorder.shared.config.Category;
+import 
org.apache.beehive.netui.tools.testrecorder.shared.config.ServerDefinition;
 
 /**
  * User: ozzy
@@ -54,6 +56,23 @@
         return new TestSuite( SchemaTest.class );
     }
 
+    public void testServerDef() {
+        log.info( "\ntestServerDef()" );
+        File file = new File( getDataDir(), Constants.SERVER_FILE );
+        log.info( "file( " + file + " )" );
+        ServerDefinition server = null;
+        try {
+            server = XMLHelper.getServerDefinition( file );
+        }
+        catch ( ConfigException e ) {
+            assertTrue( e );
+        }
+        catch ( IOException ioe ) {
+            assertTrue( ioe );
+        }
+        log.debug( "server( " + server + " )" );
+    }
+
     public void testTestDefinitions() {
         log.info( "\ntestTestDefinitions()" );
         File file = new File( getDataDir(), "config1.xml" );

Reply via email to