TCK Migration: Move first set of REST tck tests from jakartaee-tck  (#1002)

* Initial changes lifted directly from jakartaee-tck repo to run com.sun.ts.tests.jaxrs.api.rs.core.responsebuilder tests

jakartaee-tck(source) - > jaxrs-api (target)

src/com/sun/ts/tests/jaxrs/api/rs/core/responsebuilder - > jaxrs-api/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/responsebuilder
src/com/sun/ts/tests/jaxrs/api/rs/core/responseclient - > jaxrs-api/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/responseclient
src/com/sun/ts/tests/common/webclient - > jaxrs-api/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient
src.../tests/jaxrs/common -> common
src.../tests/jaxrs/common/util -> common/util
src/com/sun/ts/lib/porting -> lib/porting/
src.../lib/util -> lib/util
src.../tests/servlet/common/util/Data.java -> lib/util/Data.java

* changes to run tck tests at jakarta.ws.rs.tck.api.rs.core.responsebuilder

* files added directly from jakartaee-tck repo to run set of ee tests

* use arquillian to start running tests in ee/rs/core/request/ using gf container

* temp fix to get server tests passing

* address some of the pending issues and review comments

 - Use system properties set in jersey-tck/pom.xml (hostname, portnumber, servlet adaptor)
 - replace the jersey jars in glassfish bundle used as container, so the server tests are run against the expected jersey jars.
 - Bring back Fault class extending Exception that will be thrown if test fails. The original source of Fault class is https://github.com/eclipse-ee4j/jakartaee-tck/blob/master/src/com/sun/ts/lib/harness/EETest.java
 - Uncomment one more test in request/JAXRSClientIT (was commented by mistake)

* adress Markus review comments

- fix pom file indentation
- use latest versions of junit-jupiter jars
- use jdk11 version (glassfish 6.1)
- remove arquillian.xml for now

* move glassfish specific jar out of jaxrs tck module

* add junit version range, remove redundant compiler version

* address recent review comments

- set porting.ts.url.class.1 as system variable
- remove commented code

* add more client tests from api.rs.core.uribuilder, improve logging

- added new system variable junit.log.traceflag for logging TestUtil.logTrace,
- printing more logs using TestUtil.logMsg
- added client tests from api.rs.core.uribuilder

* edit web xml template before deployment

- removed the hardcoded web xml string
- move web.xml.template to resources

* Tests at ee/rs/client/asyncinvoker and associated files lifted directly from jakartaee-tck

* fix to run tests at jakarta/ws/rs/tck/ee/rs/client/asyncinvoker

* fix to run the tests in api/rs/core/responseclient (85 tests)

- test files api/rs/core/responseclient were already moved, now enabled them to run

* reverting bad change in previous commit to use wrong jdk version

* disabling 13 failing tests to address later, add jaxrs api jar to glassfish for container tests
diff --git a/jaxrs-tck/pom.xml b/jaxrs-tck/pom.xml
index c7ee0a9..cb39cad 100644
--- a/jaxrs-tck/pom.xml
+++ b/jaxrs-tck/pom.xml
@@ -17,7 +17,8 @@
 
 -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
     <groupId>jakarta.ws.rs</groupId>
@@ -29,8 +30,9 @@
     <url>https://github.com/eclipse-ee4j/jaxrs-api</url>
 
     <properties>
-        <maven.compiler.source>1.8</maven.compiler.source>
-        <maven.compiler.target>1.8</maven.compiler.target>
+        <maven.compiler.source>11</maven.compiler.source>
+        <maven.compiler.target>11</maven.compiler.target>
+        <junit.jupiter.version>[5.7.2, 5.8-A00)</junit.jupiter.version>
     </properties>
 
     <organization>
@@ -78,6 +80,20 @@
         <tag>HEAD</tag>
     </scm>
 
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>2.3.2</version>
+            </plugin>
+            <plugin>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>3.0.0-M5</version>
+            </plugin>
+
+        </plugins>
+    </build>
+
     <dependencies>
         <dependency>
             <groupId>jakarta.ws.rs</groupId>
@@ -87,8 +103,21 @@
 
         <dependency>
             <groupId>org.junit.jupiter</groupId>
-            <artifactId>junit-jupiter-api</artifactId>
-            <version>[5.5.2, 5.6-A00)</version>
+            <artifactId>junit-jupiter</artifactId>
+            <version>${junit.jupiter.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.junit.platform</groupId>
+            <artifactId>junit-platform-launcher</artifactId>
+            <version>1.7.2</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-httpclient</groupId>
+            <artifactId>commons-httpclient</artifactId>
+            <version>3.1</version>
         </dependency>
 
         <dependency>
@@ -96,5 +125,18 @@
             <artifactId>hamcrest-library</artifactId>
             <version>[2.2, 2.3-A00)</version>
         </dependency>
+
+        <dependency>
+            <groupId>org.jboss.arquillian.junit5</groupId>
+            <artifactId>arquillian-junit5-container</artifactId>
+            <version>1.7.0.Alpha10</version>
+        </dependency>
+
+        <dependency>
+            <groupId>jakarta.annotation</groupId>
+            <artifactId>jakarta.annotation-api</artifactId>
+            <version>2.0.0</version>
+        </dependency>
+
     </dependencies>
 </project>
\ No newline at end of file
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/responsebuilder/BuilderClientIT.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/responsebuilder/BuilderClientIT.java
new file mode 100644
index 0000000..caf9d47
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/responsebuilder/BuilderClientIT.java
@@ -0,0 +1,437 @@
+/*
+ * Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.api.rs.core.responsebuilder;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.text.DateFormat;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.TreeSet;
+
+import jakarta.ws.rs.tck.api.rs.core.responseclient.VerificationResult;
+import jakarta.ws.rs.tck.common.impl.SinglevaluedMap;
+import jakarta.ws.rs.tck.common.util.JaxrsUtil;
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.AfterEach;
+
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.Invocation;
+import jakarta.ws.rs.client.Invocation.Builder;
+import jakarta.ws.rs.client.WebTarget;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.Link;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.Response.ResponseBuilder;
+import jakarta.ws.rs.core.Variant;
+import jakarta.ws.rs.ext.RuntimeDelegate;
+
+public class BuilderClientIT
+    extends jakarta.ws.rs.tck.api.rs.core.responseclient.JAXRSClientIT {
+
+  @BeforeEach
+  void logStartTest(TestInfo testInfo) {
+    TestUtil.logMsg("STARTING TEST : "+testInfo.getDisplayName());
+  }
+
+  @AfterEach
+  void logFinishTest(TestInfo testInfo) {
+    TestUtil.logMsg("FINISHED TEST : "+testInfo.getDisplayName());
+  }
+  
+  /*
+   * @testName: statusTest1
+   *
+   * @assertion_ids: JAXRS:JAVADOC:131; JAXRS:JAVADOC:153; JAXRS:JAVADOC:141;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:125; JAXRS:JAVADOC:124;
+   *
+   * @test_Strategy: Create an instance of ResponseBuilder Response.ok();
+   * Setting status using ResponseBuilder.status(int); verify that correct
+   * status code is returned
+   */
+  @Test
+  public void statusTest1() throws Fault {
+    VerificationResult result = new VerificationResult();
+    Response resp = null;
+    ResponseBuilder respb = null;
+    for (int status : status_codes) {
+      respb = Response.ok();
+      respb = respb.status(status);
+      resp = respb.build();
+      result.append(verifyStatus(resp, status));
+    }
+    logMsg(result);
+    assertTrue(result.pass);
+  }
+
+  /*
+   * @testName: statusTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:131; JAXRS:JAVADOC:154; JAXRS:JAVADOC:141;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of ResponseBuilder Response.ok();
+   * Setting status using ResponseBuilder.status(Status); verify that correct
+   * status code is returned
+   */
+  @Test
+  public void statusTest2() throws Fault {
+    VerificationResult result = new VerificationResult();
+    Response resp = null;
+    ResponseBuilder respb = null;
+    for (int i = 0; i < status_codes.length - 1; i++) {
+      respb = Response.ok();
+      respb = respb.status(resp_status[i]);
+      resp = respb.build();
+      result.append(verifyStatus(resp, status_codes[i]));
+    }
+    logMsg(result);
+    assertTrue(result.pass);
+  }
+
+  /*
+   * @testName: expiresTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:147;
+   * 
+   * @test_Strategy: Set Expires to ResponseBuilder, build a response and check
+   * expires timestamp.
+   */
+  @Test
+  public void expiresTest() throws Fault {
+    Date now = Calendar.getInstance().getTime();
+    ResponseBuilder rs = Response.ok();
+    rs.expires(now);
+    Response response = rs.build();
+    MultivaluedMap<String, Object> metadata = response.getMetadata();
+    if (metadata == null)
+      fail("No metadata in response");
+    List<Object> expires = response.getMetadata().get("Expires");
+    if (expires == null || expires.isEmpty())
+      fail("No Expires property in metadata");
+    boolean condition = false;
+    Object fetched = expires.iterator().next();
+    if (Date.class.isInstance(fetched))
+      condition = ((Date) fetched).compareTo(now) == 0;
+    else if (String.class.isInstance(fetched))
+      condition = formats(now).contains(fetched.toString());
+    else
+      fail("Fetched object not recognised");
+
+    assertTrue(condition, "Expires value not matched, set: " + now.toString()+
+        "fetched:"+ fetched.toString());
+    logMsg("Set and fetched expire dates matched");
+  }
+
+  /*
+   * @testName: allowStringArrayTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:875;
+   * 
+   * @test_Strategy: Set the list of allowed methods for the resource.
+   */
+  @Test
+  public void allowStringArrayTest() throws Fault {
+    String[] methods = { Request.OPTIONS.name(), Request.TRACE.name() };
+    ResponseBuilder rb = RuntimeDelegate.getInstance().createResponseBuilder();
+    Response response = rb.allow(methods).build();
+    Set<String> set = response.getAllowedMethods();
+    String responseMethods = JaxrsUtil.iterableToString(" ", set);
+
+    for (String method : methods) {
+      assertContains(responseMethods, method, "Expected allow method", method,
+          "was not found in response allowed methods", responseMethods);
+      logMsg("Found expected allowed method", method);
+    }
+  }
+
+  /*
+   * @testName: allowStringArrayTruncateDuplicatesTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:875;
+   * 
+   * @test_Strategy: Set the list of allowed methods for the resource.
+   */
+  @Test
+  public void allowStringArrayTruncateDuplicatesTest() throws Fault {
+    String[] methods = { Request.OPTIONS.name(), Request.OPTIONS.name() };
+    ResponseBuilder rb = RuntimeDelegate.getInstance().createResponseBuilder();
+    Response response = rb.allow(methods).build();
+    Set<String> set = response.getAllowedMethods();
+    assertEqualsInt(1, set.size(), "Only one allow method should be present");
+    assertEquals(set.iterator().next(), Request.OPTIONS.name(),
+        Request.OPTIONS.name(), "has not been found in allowed methods");
+    logMsg(Request.OPTIONS.name(), "has been found in allowed methods");
+  }
+
+  /*
+   * @testName: allowStringArrayNullRemovesAllTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:875;
+   * 
+   * @test_Strategy: if null any existing allowed method list will be removed.
+   */
+  @Test
+  public void allowStringArrayNullRemovesAllTest() throws Fault {
+    String[] methods = { Request.OPTIONS.name(), Request.GET.name() };
+    ResponseBuilder rb = RuntimeDelegate.getInstance().createResponseBuilder();
+    Response response = rb.allow(methods).allow((String[]) null).build();
+    Set<String> set = response.getAllowedMethods();
+    assertEqualsInt(0, set.size(), "No one allow method should be present");
+    logMsg("Allowed methods has been removed by null value as expected");
+  }
+
+  /*
+   * @testName: allowStringSetTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:876;
+   * 
+   * @test_Strategy: Set the list of allowed methods for the resource.
+   */
+  @Test
+  public void allowStringSetTest() throws Fault {
+    Set<String> methods = new TreeSet<String>();
+    methods.add(Request.OPTIONS.name());
+    methods.add(Request.TRACE.name());
+
+    ResponseBuilder rb = RuntimeDelegate.getInstance().createResponseBuilder();
+    Response response = rb.allow(methods).build();
+    Set<String> set = response.getAllowedMethods();
+    String responseMethods = JaxrsUtil.iterableToString(" ", set);
+
+    for (String method : methods) {
+      assertContains(responseMethods, method, "Expected allow method", method,
+          "was not found in response allowed methods", responseMethods);
+      logMsg("Found expected allowed method", method);
+    }
+  }
+
+  /*
+   * @testName: allowStringSetNullRemovesAllTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:876;
+   * 
+   * @test_Strategy: if null any existing allowed method list will be removed.
+   */
+  @Test
+  public void allowStringSetNullRemovesAllTest() throws Fault {
+    Set<String> methods = new TreeSet<String>();
+    methods.add(Request.OPTIONS.name());
+    methods.add(Request.TRACE.name());
+
+    ResponseBuilder rb = RuntimeDelegate.getInstance().createResponseBuilder();
+    Response response = rb.allow(methods).allow((Set<String>) null).build();
+    Set<String> set = response.getAllowedMethods();
+    assertEqualsInt(0, set.size(), "No one allow method should be present");
+    logMsg("Allowed methods has been removed by null value as expected");
+  }
+
+  /*
+   * @testName: encodingTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:878;
+   * 
+   * @test_Strategy: Set the message entity content encoding.
+   */
+  @Test
+  public void encodingTest() throws Fault {
+    String[] encodings = { "gzip", "ccitt", "pic" };
+    VerificationResult vr = new VerificationResult();
+    for (String encoding : encodings) {
+      Response response = Response.ok().encoding(encoding).build();
+      vr.append(verifyEncoding(response, Collections.singletonList(encoding)));
+    }
+    logMsg(vr.message);
+    assertTrue(vr.pass);
+    logMsg("Found expected encodings");
+  }
+
+  /*
+   * @testName: linkUriStringTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:880;
+   * 
+   * @test_Strategy: Add a link header.
+   */
+  @Test
+  public void linkUriStringTest() throws Fault {
+    URI uri = null;
+    try {
+      uri = new URI(URL);
+    } catch (URISyntaxException e) {
+      fail(e.getMessage());
+    }
+    String rel = "REL";
+    Response response = Response.ok().link(uri, rel).build();
+    Link link = response.getLink(rel);
+    assertTrue(link != null, "link is null");
+    assertTrue(link.toString().contains(URL), "link"+ link+
+        "does not contain expected"+ URL);
+    logMsg("Found expected link", link);
+  }
+
+  /*
+   * @testName: linkStringStringTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:881;
+   * 
+   * @test_Strategy: Add a link header.
+   */
+  @Test
+  public void linkStringStringTest() throws Fault {
+    String rel = "REL";
+    Response response = Response.ok().link(URL, rel).build();
+    Link link = response.getLink(rel);
+    assertTrue(link != null, "link is null");
+    assertTrue(link.toString().contains(URL), "link"+ link+
+        "does not contain expected"+ URL);
+    logMsg("Found expected link", link);
+  }
+
+  /*
+   * @testName: linksTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:882;
+   * 
+   * @test_Strategy: Add one or more link headers.
+   */
+  @Test
+  public void linksTest() throws Fault {
+    String rel = "REL";
+    Link link1 = Link.fromUri(URL).rel(rel + "1").build();
+    Link link11 = Link.fromUri(URL).rel(rel + "11").build();
+    Link link2 = Link.fromUri(URL + "/link2").rel(rel + "2").build();
+
+    Response response = Response.ok().links(link1, link11, link2).build();
+    Link link = response.getLink(rel + "1");
+    assertTrue(link != null, "link is null");
+    assertTrue(link.toString().contains(URL), "link"+ link+
+        "does not contain expected"+ URL);
+    link = response.getLink(rel + "11");
+    assertTrue(link != null, "link is null");
+    assertTrue(link.toString().contains(URL), "link"+ link+
+        "does not contain expected"+ URL);
+    link = response.getLink(rel + "2");
+    assertTrue(link != null, "link is null");
+    assertTrue(link.toString().contains(URL + "/link2"), "link"+ link+
+        "does not contain expected"+ URL + "/link2");
+
+    logMsg("Found expected links");
+  }
+
+  /*
+   * @testName: replaceAllTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:883;
+   * 
+   * @test_Strategy: Replaces all existing headers with the newly supplied
+   * headers.
+   */
+  @Test
+  public void replaceAllTest() throws Fault {
+    String[] headers = { "header1", "header2", "header3" };
+    String header99 = "header99";
+    MultivaluedMap<String, Object> mv = new SinglevaluedMap<String, Object>();
+    mv.add(header99, header99);
+    Response response = Response.ok().header(headers[0], headers[0])
+        .header(headers[1], headers[1]).header(headers[2], headers[2])
+        .replaceAll(mv).build();
+    for (String header : headers)
+      assertTrue(response.getHeaderString(header) == null,
+          "response contains non replaced header" + header);
+
+    assertTrue(response.getHeaderString(header99).equals(header99),
+        "response does not contain header from replacedAll map"+ header99);
+  }
+
+  /*
+   * @testName: replaceAllByNullTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:883;
+   * 
+   * @test_Strategy: Replaces all existing headers with the newly supplied
+   * headers. if null all existing headers will be removed.
+   */
+  @Test
+  public void replaceAllByNullTest() throws Fault {
+    String[] headers = { "header1", "header2", "header3" };
+    Response response = Response.ok().header(headers[0], headers[0])
+        .header(headers[1], headers[1]).header(headers[2], headers[2])
+        .replaceAll(null).build();
+    for (String header : headers)
+      assertTrue(response.getHeaderString(header) == null,
+          "response contains non replaced header"+ header);
+  }
+
+  /*
+   * @testName: variantsTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:884;
+   * 
+   * @test_Strategy: Add a Vary header that lists the available variants.
+   */
+  @Test
+  public void variantsTest() throws Fault {
+    List<String> encoding = Arrays.asList("gzip", "compress");
+    List<String> vars = Arrays.asList(HttpHeaders.ACCEPT_LANGUAGE,
+        HttpHeaders.ACCEPT_ENCODING);
+    MediaType mt = MediaType.APPLICATION_JSON_TYPE;
+    ResponseBuilder rb = Response.ok();
+    rb = rb.variants(getVariantList(encoding, mt).toArray(new Variant[0]));
+    Response response = rb.build();
+    VerificationResult result = new VerificationResult();
+    result.append(verifyVary(response, vars));
+    logMsg(result.message);
+    assertTrue(result.pass);
+  }
+
+  // //////////////////////////////////////////////////////////////////
+
+  private static String formats(Date date) {
+    DateFormat format;
+    TestUtil.logMsg("Creating possible string format list");
+    StringBuilder sb = new StringBuilder();
+    for (String tz : TimeZone.getAvailableIDs()) {
+      format = JaxrsUtil.createDateFormat(TimeZone.getTimeZone(tz));
+      sb.append(format.format(date));
+    }
+    return sb.toString();
+  }
+
+  protected Invocation.Builder invocation() {
+    Client client = ClientBuilder.newClient();
+    WebTarget target = client.target(URL);
+    Builder b = target.request();
+    return b;
+  }
+
+  static final String URL = "http://localhost:888/noUrl";
+}
\ No newline at end of file
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/responseclient/JAXRSClientIT.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/responseclient/JAXRSClientIT.java
new file mode 100644
index 0000000..00ebe0b
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/responseclient/JAXRSClientIT.java
@@ -0,0 +1,2565 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.api.rs.core.responseclient;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import jakarta.ws.rs.tck.common.JAXRSCommonClient;
+import jakarta.ws.rs.tck.common.client.JaxrsCommonClient;
+import jakarta.ws.rs.tck.common.provider.StringBean;
+import jakarta.ws.rs.tck.common.provider.StringBeanRuntimeDelegate;
+import jakarta.ws.rs.tck.common.util.JaxrsUtil;
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.AfterEach;
+
+import jakarta.ws.rs.core.CacheControl;
+import jakarta.ws.rs.core.Cookie;
+import jakarta.ws.rs.core.EntityTag;
+import jakarta.ws.rs.core.GenericEntity;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.Link;
+import jakarta.ws.rs.core.Link.Builder;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.NewCookie;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.Response.Status;
+import jakarta.ws.rs.core.Response.StatusType;
+import jakarta.ws.rs.core.Variant;
+import jakarta.ws.rs.ext.RuntimeDelegate;
+
+public class JAXRSClientIT extends JAXRSCommonClient {
+
+  private static final long serialVersionUID = -2343034378084516380L;
+
+  // name it to ensure sorting
+  protected final Response.Status[] resp_status = { Response.Status.OK,
+      Response.Status.CREATED, Response.Status.ACCEPTED,
+      Response.Status.NO_CONTENT, Response.Status.RESET_CONTENT,
+      Response.Status.PARTIAL_CONTENT, Response.Status.MOVED_PERMANENTLY,
+      Response.Status.FOUND, Response.Status.SEE_OTHER,
+      Response.Status.NOT_MODIFIED, Response.Status.USE_PROXY,
+      Response.Status.TEMPORARY_REDIRECT, Response.Status.BAD_REQUEST,
+      Response.Status.UNAUTHORIZED, Response.Status.PAYMENT_REQUIRED,
+      Response.Status.FORBIDDEN, Response.Status.NOT_FOUND,
+      Response.Status.METHOD_NOT_ALLOWED, Response.Status.NOT_ACCEPTABLE,
+      Response.Status.PROXY_AUTHENTICATION_REQUIRED,
+      Response.Status.REQUEST_TIMEOUT, Response.Status.CONFLICT,
+      Response.Status.GONE, Response.Status.LENGTH_REQUIRED,
+      Response.Status.PRECONDITION_FAILED,
+      Response.Status.REQUEST_ENTITY_TOO_LARGE,
+      Response.Status.REQUEST_URI_TOO_LONG,
+      Response.Status.UNSUPPORTED_MEDIA_TYPE,
+      Response.Status.REQUESTED_RANGE_NOT_SATISFIABLE,
+      Response.Status.EXPECTATION_FAILED, Response.Status.PRECONDITION_REQUIRED,
+      Response.Status.TOO_MANY_REQUESTS,
+      Response.Status.REQUEST_HEADER_FIELDS_TOO_LARGE,
+      Response.Status.INTERNAL_SERVER_ERROR, Response.Status.NOT_IMPLEMENTED,
+      Response.Status.BAD_GATEWAY, Response.Status.SERVICE_UNAVAILABLE,
+      Response.Status.GATEWAY_TIMEOUT,
+      Response.Status.HTTP_VERSION_NOT_SUPPORTED,
+      Response.Status.NETWORK_AUTHENTICATION_REQUIRED };
+
+  // name it to ensure sorting
+  protected final int[] status_codes = { 200, 201, 202, 204, 205, 206, 301, 302,
+      303, 304, 305, 307, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410,
+      411, 412, 413, 414, 415, 416, 417, 428, 429, 431, 500, 501, 502, 503, 504,
+      505, 511 };
+
+  // name it to ensure sorting
+  protected final Response.Status.Family[] status_family = {
+      Response.Status.Family.SUCCESSFUL, Response.Status.Family.SUCCESSFUL,
+      Response.Status.Family.SUCCESSFUL, Response.Status.Family.SUCCESSFUL,
+      Response.Status.Family.SUCCESSFUL, Response.Status.Family.SUCCESSFUL,
+      Response.Status.Family.REDIRECTION, Response.Status.Family.REDIRECTION,
+      Response.Status.Family.REDIRECTION, Response.Status.Family.REDIRECTION,
+      Response.Status.Family.REDIRECTION, Response.Status.Family.REDIRECTION,
+      Response.Status.Family.CLIENT_ERROR, Response.Status.Family.CLIENT_ERROR,
+      Response.Status.Family.CLIENT_ERROR, Response.Status.Family.CLIENT_ERROR,
+      Response.Status.Family.CLIENT_ERROR, Response.Status.Family.CLIENT_ERROR,
+      Response.Status.Family.CLIENT_ERROR, Response.Status.Family.CLIENT_ERROR,
+      Response.Status.Family.CLIENT_ERROR, Response.Status.Family.CLIENT_ERROR,
+      Response.Status.Family.CLIENT_ERROR, Response.Status.Family.CLIENT_ERROR,
+      Response.Status.Family.CLIENT_ERROR, Response.Status.Family.CLIENT_ERROR,
+      Response.Status.Family.CLIENT_ERROR, Response.Status.Family.CLIENT_ERROR,
+      Response.Status.Family.CLIENT_ERROR, Response.Status.Family.CLIENT_ERROR,
+      Response.Status.Family.CLIENT_ERROR, Response.Status.Family.CLIENT_ERROR,
+      Response.Status.Family.CLIENT_ERROR, Response.Status.Family.SERVER_ERROR,
+      Response.Status.Family.SERVER_ERROR, Response.Status.Family.SERVER_ERROR,
+      Response.Status.Family.SERVER_ERROR, Response.Status.Family.SERVER_ERROR,
+      Response.Status.Family.SERVER_ERROR,
+      Response.Status.Family.SERVER_ERROR };
+
+  protected final Response.Status.Family[] status_family_list = {
+      Response.Status.Family.CLIENT_ERROR, Response.Status.Family.INFORMATIONAL,
+      Response.Status.Family.OTHER, Response.Status.Family.REDIRECTION,
+      Response.Status.Family.SERVER_ERROR, Response.Status.Family.SUCCESSFUL };
+
+  protected final String[] status = { "OK", "Created", "Accepted", "No Content",
+      "Reset Content", "Partial Content", "Moved Permanently", "Found",
+      "See Other", "Not Modified", "Use Proxy", "Temporary Redirect",
+      "Bad Request", "Unauthorized", "Payment Required", "Forbidden",
+      "Not Found", "Method Not Allowed", "Not Acceptable",
+      "Proxy Authentication Required", "Request Timeout", "Conflict", "Gone",
+      "Length Required", "Precondition Failed", "Request Entity Too Large",
+      "Request-URI Too Long", "Unsupported Media Type",
+      "Requested Range Not Satisfiable", "Expectation Failed",
+      "Precondition Required", "Too Many Requests",
+      "Request Header Fields Too Large", "Internal Server Error",
+      "Not Implemented", "Bad Gateway", "Service Unavailable",
+      "Gateway Timeout", "HTTP Version Not Supported",
+      "Network Authentication Required" };
+
+
+  @BeforeEach
+  void logStartTest(TestInfo testInfo) {
+    TestUtil.logMsg("STARTING TEST : "+testInfo.getDisplayName());
+  }
+
+  @AfterEach
+  void logFinishTest(TestInfo testInfo) {
+    TestUtil.logMsg("FINISHED TEST : "+testInfo.getDisplayName());
+  }
+
+  /*
+   * @class.setup_props: webServerHost; webServerPort; 
+   */
+  /* Run test */
+
+  /*
+   * @testName: okTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:131; JAXRS:JAVADOC:141; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using Response.ok().build()
+   * verify that correct status code is returned
+   */
+  @Test
+  public void okTest1() throws Fault {
+    VerificationResult result;
+    Response response = null;
+    int status = 200;
+    response = Response.ok().build();
+    result = verifyStatus(response, status);
+    logMsg(result.message);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: okTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:132; JAXRS:JAVADOC:141; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.ok(String).build() verify that correct status code is returned
+   */
+  @Test
+  public void okTest2() throws Fault {
+    VerificationResult result;
+    Response resp = null;
+    int status = 200;
+    String content = "Test only";
+    resp = Response.ok(content).build();
+    result = verifyContent(resp, content);
+    result.append(verifyStatus(resp, status));
+    logMsg(result.message);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: okTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:134; JAXRS:JAVADOC:141; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using Response.ok(String,
+   * String).build() verify that correct status code is returned
+   */
+  @Test
+  public void okTest3() throws Fault {
+    VerificationResult result;
+    Response resp = null;
+    int status = 200;
+    String content = "Test only";
+    String type = MediaType.TEXT_PLAIN;
+    resp = Response.ok(content, type).build();
+    result = verifyContent(resp, content);
+    result.append(verifyStatus(resp, status));
+    result.append(verifyContentType(resp, Collections.singletonList(type)));
+    logMsg(result.message);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: okTest4
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:133; JAXRS:JAVADOC:141; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using Response.ok(String,
+   * MediaType).build() verify that correct status code is returned
+   */
+  @Test
+  public void okTest4() throws Fault {
+    VerificationResult result;
+    Response resp = null;
+    int status = 200;
+    String content = "Test only";
+    String type = MediaType.TEXT_PLAIN;
+    MediaType mt = new MediaType(MediaType.TEXT_PLAIN_TYPE.getType(),
+        MediaType.TEXT_PLAIN_TYPE.getSubtype());
+    resp = Response.ok(content, mt).build();
+    result = verifyContent(resp, content);
+    result.append(verifyStatus(resp, status));
+    result.append(verifyContentType(resp, Collections.singletonList(type)));
+    logMsg(result.message);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: okTest5
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:135; JAXRS:JAVADOC:141; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125; JAXRS:JAVADOC:91; JAXRS:JAVADOC:268;
+   * JAXRS:JAVADOC:267; JAXRS:JAVADOC:266; JAXRS:JAVADOC:265; JAXRS:JAVADOC:263;
+   * JAXRS:JAVADOC:264;
+   * 
+   * @test_Strategy: Create an instance of Response using Response.ok(String,
+   * Variant).build() verify that correct status code is returned
+   */
+  @Test
+  public void okTest5() throws Fault {
+    VerificationResult result = new VerificationResult();
+    Response resp = null;
+    int status = 200;
+    String content = "Test Only";
+    List<String> encoding = Arrays.asList("gzip", "compress");
+
+    MediaType mt = new MediaType("text", "plain");
+    List<Variant> vts = getVariantList(encoding, mt);
+
+    for (int i = 0; i < vts.size(); i++) {
+      Variant vt = vts.get(i);
+      resp = Response.ok(content, vt).build();
+      result.append(verifyContent(resp, content));
+      result.append(verifyStatus(resp, status));
+      result.append(verifyEncoding(resp, encoding));
+      result.append(verifyLanguage(resp, getLangList()));
+      result.append(
+          verifyContentType(resp, Collections.singletonList(mt.toString())));
+    }
+    logMsg(result.message);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: noContentTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:126; JAXRS:JAVADOC:141; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.noContent().build() verify that correct status code is returned
+   */
+  @Test
+  public void noContentTest() throws Fault {
+    VerificationResult result;
+
+    Response resp = null;
+    int status = 204;
+
+    resp = Response.noContent().build();
+    result = verifyStatus(resp, status);
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: notAcceptableTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:127; JAXRS:JAVADOC:141; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125; JAXRS:JAVADOC:91; JAXRS:JAVADOC:268;
+   * JAXRS:JAVADOC:267; JAXRS:JAVADOC:266; JAXRS:JAVADOC:265; JAXRS:JAVADOC:263;
+   * JAXRS:JAVADOC:264;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.notAcceptable(vts).build() verify that correct status code is
+   * returned
+   */
+  @Test
+  public void notAcceptableTest() throws Fault {
+    VerificationResult result;
+
+    Response resp = null;
+    int status = 406;
+
+    List<String> encoding = Arrays.asList("gzip", "compress");
+
+    MediaType mt = new MediaType("text", "plain");
+    List<Variant> vts = getVariantList(encoding, mt);
+
+    resp = Response.notAcceptable(vts).build();
+    result = verifyStatus(resp, status);
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: notModifiedTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:128; JAXRS:JAVADOC:141; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.notModified().build() verify that correct status code is returned
+   */
+  @Test
+  public void notModifiedTest1() throws Fault {
+    VerificationResult result;
+
+    Response resp = null;
+    int status = 304;
+    resp = Response.notModified().build();
+
+    result = verifyStatus(resp, status);
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: notModifiedTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:130; JAXRS:JAVADOC:141; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.notModified(String).build() verify that correct status code is
+   * returned
+   */
+  @Test
+  public void notModifiedTest2() throws Fault {
+    VerificationResult result;
+    Response resp = null;
+    int status = 304;
+    String tags = "TestOnly";
+    HashMap<String, String> expected_map = new HashMap<String, String>();
+    expected_map.put("ETAG", tags);
+
+    resp = Response.notModified(tags).build();
+    result = verifyStatus(resp, status);
+    result.append(verifyHeaders(resp, expected_map));
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: notModifiedTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:129; JAXRS:JAVADOC:141; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.notModified(EntityTag).build() verify that correct status code is
+   * returned
+   */
+  @Test
+  public void notModifiedTest3() throws Fault {
+    VerificationResult result;
+    Response resp = null;
+    int status = 304;
+    String value = "TestOnly";
+
+    EntityTag et = new EntityTag(value);
+
+    HashMap<String, String> expected_map = new HashMap<String, String>();
+    expected_map.put("ETAG", value);
+
+    resp = Response.notModified(et).build();
+    result = verifyStatus(resp, status);
+    result.append(verifyHeaders(resp, expected_map));
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: statusTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:123; JAXRS:JAVADOC:124;
+   * JAXRS:JAVADOC:125; JAXRS:SPEC:14.2;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.status(int).build() verify that correct status code is returned
+   */
+  @Test
+  public void statusTest1() throws Fault {
+    VerificationResult result = new VerificationResult();
+    Response resp = null;
+
+    for (int status : status_codes) {
+      resp = Response.status(status).build();
+      result.append(verifyStatus(resp, status));
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: statusTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:138; JAXRS:JAVADOC:123; JAXRS:JAVADOC:124;
+   * JAXRS:JAVADOC:125; JAXRS:SPEC:14.2;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.status(Response.Status).build() verify that correct status code is
+   * returned
+   */
+  @Test
+  public void statusTest2() throws Fault {
+    VerificationResult result = new VerificationResult();
+    Response resp = null;
+
+    for (int i = 0; i < status_codes.length; i++) {
+      resp = Response.status(resp_status[i]).build();
+      result.append(verifyStatus(resp, status_codes[i]));
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: statusTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:131; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125; JAXRS:SPEC:14.2;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.ResponseBuilder.status(int).build() verify that correct status
+   * code is returned
+   */
+  @Test
+  public void statusTest3() throws Fault {
+    VerificationResult result = new VerificationResult();
+    Response resp = null;
+
+    for (int status : status_codes) {
+      resp = Response.ok().status(status).build();
+      result.append(verifyStatus(resp, status));
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: statusTest4
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:138; JAXRS:JAVADOC:131; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125; JAXRS:SPEC:14.2;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.ResponseBuilder.status(Response.Status).build() verify that
+   * correct status code is returned
+   */
+  @Test
+  public void statusTest4() throws Fault {
+    VerificationResult result = new VerificationResult();
+    Response resp = null;
+
+    for (int i = 0; i < status_codes.length; i++) {
+      resp = Response.ok().status(resp_status[i]).build();
+      result.append(verifyStatus(resp, status_codes[i]));
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: createdTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:121; JAXRS:JAVADOC:141; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.created(URI).build() verify that correct status code is returned
+   */
+  @Test
+  public void createdTest() throws Fault {
+    VerificationResult result = new VerificationResult();
+
+    List<String> uri_expected = Arrays.asList("mailto:java-net@java.sun.com",
+        "news:comp.lang.java", "urn:isbn:096139210x",
+        "http://java.sun.com/j2se/1.3/",
+        "docs/guide/collections/designfaq.html#28",
+        "../../../demo/jfc/SwingSet2/src/SwingSet2.java", "file:///~/calendar");
+
+    URI test_uri = null;
+    for (String uri_string : uri_expected) {
+      try {
+        test_uri = new URI(uri_string);
+      } catch (URISyntaxException ex) {
+        result.message.append("Unexpected exception thrown:")
+            .append(ex.getMessage());
+        result.pass = false;
+      }
+      Response resp = Response.created(test_uri).build();
+
+      HashMap<String, String> expected_map = new HashMap<String, String>();
+      expected_map.put("Location", uri_string);
+      result.append(verifyStatus(resp, 201));
+      result.append(verifyHeaders(resp, expected_map));
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: serverErrorTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:137; JAXRS:JAVADOC:141; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.serverError().build() verify that correct status code is returned
+   */
+  @Test
+  public void serverErrorTest() throws Fault {
+    VerificationResult result;
+
+    Response resp = Response.serverError().build();
+    result = verifyStatus(resp, 500);
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: seeOtherTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:136; JAXRS:JAVADOC:141; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.seeOther(URI).build() verify that correct status code is returned
+   */
+  @Test
+  public void seeOtherTest() throws Fault {
+    VerificationResult result = new VerificationResult();
+
+    URI test_uri = null;
+    try {
+      test_uri = new URI("http://java.sun.com/j2se/1.3/");
+    } catch (URISyntaxException ex) {
+      result.message.append("Unexpected exception thrown:")
+          .append(ex.getMessage());
+      result.pass = false;
+    }
+    Response resp = Response.seeOther(test_uri).build();
+
+    HashMap<String, String> expected_map = new HashMap<String, String>();
+    expected_map.put("Location", "http://java.sun.com/j2se/1.3/");
+    result.append(verifyStatus(resp, 303));
+    result.append(verifyHeaders(resp, expected_map));
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: temporaryRedirectTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:140; JAXRS:JAVADOC:141; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.temporaryRedirect(URI).build() verify that correct status code is
+   * returned
+   */
+  @Test
+  public void temporaryRedirectTest() throws Fault {
+    VerificationResult result = new VerificationResult();
+
+    URI test_uri = null;
+    try {
+      test_uri = new URI("http://java.sun.com/j2se/1.3/");
+    } catch (URISyntaxException ex) {
+      result.message.append("Unexpected exception thrown:")
+          .append(ex.getMessage());
+      result.pass = false;
+    }
+    Response resp = Response.temporaryRedirect(test_uri).build();
+
+    HashMap<String, String> expected_map = new HashMap<String, String>();
+    expected_map.put("Location", "http://java.sun.com/j2se/1.3/");
+    result.append(verifyStatus(resp, 307));
+    result.append(verifyHeaders(resp, expected_map));
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: fromResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:122; JAXRS:JAVADOC:141; JAXRS:JAVADOC:123;
+   * JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.fromResponse(Response).build() verify that correct status code is
+   * returned
+   */
+  @Test
+  public void fromResponseTest() throws Fault {
+    VerificationResult result = new VerificationResult();
+
+    int status = 200;
+    String content = "Test Only";
+    List<String> type = Arrays.asList("text/plain", "text/html");
+    List<String> encoding = Arrays.asList("gzip", "compress");
+
+    MediaType mt1 = new MediaType("text", "plain");
+    MediaType mt2 = new MediaType("text", "html");
+    List<Variant> vts = getVariantList(encoding, mt1, mt2);
+
+    for (int i = 0; i < vts.size(); i++) {
+      Variant vt = vts.get(i);
+      Response resp1 = Response.ok(content, vt).build();
+      Response resp = Response.fromResponse(resp1).build();
+      result.append(verifyContent(resp, content));
+      result.append(verifyStatus(resp, status));
+      result.append(verifyEncoding(resp, encoding));
+      result.append(verifyLanguage(resp, getLangList()));
+      result.append(verifyContentType(resp, type));
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: entityTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:146;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.ResponseBuilder.entity(String).build() verify that correct status
+   * code is returned
+   */
+  @Test
+  public void entityTest() throws Fault {
+    VerificationResult result = new VerificationResult();
+
+    int status = 200;
+    String content = "Test Only";
+
+    Response resp = Response.status(status).entity(content).build();
+    result.append(verifyContent(resp, content));
+    result.append(verifyStatus(resp, status));
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: languageTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:149;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.ResponseBuilder.language(String).build() verify that correct
+   * status code is returned
+   */
+  @Test
+  public void languageTest() throws Fault {
+    VerificationResult result = new VerificationResult();
+
+    int status = 200;
+    List<String> lang = getLangList();
+
+    for (String language : lang) {
+      Response resp = Response.status(status).language(language).build();
+      result.append(verifyStatus(resp, status));
+      result.append(verifyLanguage(resp, lang));
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: languageTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:150;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.ResponseBuilder.language(Locale).build() verify that correct
+   * status code is returned
+   */
+  @Test
+  public void languageTest1() throws Fault {
+    VerificationResult result = new VerificationResult();
+    int status = 200;
+
+    for (String language : getLangList()) {
+      Response resp = Response.status(status).language(language).build();
+      result.append(verifyStatus(resp, status));
+      result.append(verifyLanguage(resp, Arrays.asList(language)));
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: typeTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:158;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.ResponseBuilder.type(String).build() verify that correct status
+   * code is returned
+   */
+  @Test
+  public void typeTest() throws Fault {
+    VerificationResult result = new VerificationResult();
+    int status = 200;
+    String type = MediaType.TEXT_PLAIN;
+
+    Response resp = Response.status(status).type(type).build();
+    result.append(verifyStatus(resp, status));
+    result.append(verifyContentType(resp, Arrays.asList(type)));
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: typeTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:157;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.ResponseBuilder.type(MediaType).build() verify that correct status
+   * code is returned
+   */
+  @Test
+  public void typeTest1() throws Fault {
+    VerificationResult result;
+
+    int status = 200;
+    List<String> types = Arrays.asList("text/plain", "text/html");
+
+    MediaType mt1 = new MediaType("text", "plain");
+    MediaType mt2 = new MediaType("text", "html");
+
+    Response resp = Response.status(status).type(mt1).type(mt2).build();
+    result = verifyStatus(resp, status);
+    result.append(verifyContentType(resp, types));
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: tagTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:156;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.ResponseBuilder.tag(String).build() verify that correct status
+   * code is returned
+   */
+  @Test
+  public void tagTest1() throws Fault {
+    VerificationResult result;
+
+    int status = 200;
+    String tag = "TestOnly";
+    HashMap<String, String> expected_map = new HashMap<String, String>();
+    expected_map.put("ETAG", tag);
+
+    Response resp = Response.status(status).tag(tag).build();
+    result = verifyStatus(resp, status);
+    result.append(verifyHeaders(resp, expected_map));
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: tagTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:155;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.ResponseBuilder.tag(EntityTag).build() verify that correct status
+   * code is returned
+   */
+  @Test
+  public void tagTest2() throws Fault {
+    VerificationResult result;
+    int status = 200;
+    EntityTag et1 = new EntityTag("StrongEntityTagTest", true);
+    EntityTag et2 = new EntityTag("TestOnly", false);
+
+    HashMap<String, String> expected_map = new HashMap<String, String>();
+    expected_map.put("ETAG", "TestOnly");
+
+    Response resp = Response.status(status).tag(et1).tag(et2).build();
+    result = verifyStatus(resp, status);
+    result.append(verifyHeaders(resp, expected_map));
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: variantTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:159;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.status(int).variant(Variant).build() verify that correct status
+   * code is returned
+   */
+  @Test
+  public void variantTest() throws Fault {
+    VerificationResult result = new VerificationResult();
+    Response resp = null;
+    int status = 200;
+    List<String> encoding = Arrays.asList("gzip", "compress");
+
+    MediaType mt = new MediaType("text", "plain");
+    List<Variant> vts = getVariantList(encoding, mt);
+
+    for (int i = 0; i < vts.size(); i++) {
+      Variant vt = vts.get(i);
+      resp = Response.status(status).variant(vt).build();
+      verifyStatus(resp, status);
+      verifyEncoding(resp, encoding);
+      verifyLanguage(resp, getLangList());
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: variantsTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:160;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.status(int).variants(List<Variant>).build() verify that correct
+   * status code is returned
+   */
+  @Test
+  public void variantsTest() throws Fault {
+    VerificationResult result;
+    Response resp = null;
+    int status = 200;
+    // String type = "text/plain";
+    List<String> encoding = Arrays.asList("gzip", "compress");
+    List<String> vars = Arrays.asList("accept-language", "accept-encoding");
+
+    MediaType mt = new MediaType("text", "plain");
+    List<Variant> vts = getVariantList(encoding, mt);
+    resp = Response.status(status).variants(vts).build();
+    result = verifyStatus(resp, status);
+    result.append(verifyVary(resp, vars));
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: locationTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:152;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.status(status).location(URI).build() verify that correct status
+   * code is returned
+   */
+  @Test
+  public void locationTest() throws Fault {
+    VerificationResult result = new VerificationResult();
+    int status = 200;
+    List<String> uri_expected = Arrays.asList("mailto:java-net@java.sun.com",
+        "news:comp.lang.java", "urn:isbn:096139210x",
+        "http://java.sun.com/j2se/1.3/",
+        "docs/guide/collections/designfaq.html#28",
+        "../../../demo/jfc/SwingSet2/src/SwingSet2.java", "file:///~/calendar");
+
+    URI test_uri = null;
+    for (String uri_string : uri_expected) {
+      try {
+        test_uri = new URI(uri_string);
+      } catch (URISyntaxException ex) {
+        result.message.append("Unexpected exception thrown:")
+            .append(ex.getMessage());
+        result.pass = false;
+      }
+      Response resp = Response.status(status).location(test_uri).build();
+
+      HashMap<String, String> expected_map = new HashMap<String, String>();
+      expected_map.put("Location", uri_string);
+      result.append(verifyStatus(resp, status));
+      result.append(verifyHeaders(resp, expected_map));
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: contentLocationTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:144;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.status(status).contentLocation(URI).build() verify that correct
+   * status code is returned
+   */
+  @Test
+  public void contentLocationTest() throws Fault {
+    VerificationResult result = new VerificationResult();
+    int status = 200;
+    List<String> uri_expected = Arrays.asList("mailto:java-net@java.sun.com",
+        "news:comp.lang.java", "urn:isbn:096139210x",
+        "http://java.sun.com/j2se/1.3/",
+        "docs/guide/collections/designfaq.html#28",
+        "../../../demo/jfc/SwingSet2/src/SwingSet2.java", "file:///~/calendar");
+
+    URI test_uri = null;
+    for (String uri_string : uri_expected) {
+      try {
+        test_uri = new URI(uri_string);
+      } catch (URISyntaxException ex) {
+        result.message.append("Unexpected exception thrown:")
+            .append(ex.getMessage());
+        result.pass = false;
+      }
+      Response resp = Response.status(status).contentLocation(test_uri).build();
+
+      HashMap<String, String> expected_map = new HashMap<String, String>();
+      expected_map.put("Content-Location", uri_string);
+      result.append(verifyStatus(resp, 200));
+      result.append(verifyHeaders(resp, expected_map));
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: cacheControlTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:142;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.ResponseBuilder.cacheControl(String).build() verify that correct
+   * status code is returned
+   */
+  @Test
+  public void cacheControlTest() throws Fault {
+    VerificationResult result;
+    int status = 200;
+    boolean nostore = true;
+
+    CacheControl ccl4 = new CacheControl();
+    ccl4.setNoStore(nostore);
+
+    List<String> ccl = Arrays.asList("no-store", "no-transform");
+
+    Response resp = Response.status(status).cacheControl(ccl4).build();
+    result = verifyStatus(resp, status);
+    result.append(verifyCacheControl(resp, ccl));
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: cookieTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:145;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.ResponseBuilder.cookie(NewCookie).build() verify that correct
+   * status code is returned
+   */
+  @Test
+  public void cookieTest() throws Fault {
+    VerificationResult result;
+    int status = 200;
+
+    String name = "name_1";
+    String value = "value_1";
+    // int maxage = jakarta.ws.rs.core.NewCookie.DEFAULT_MAX_AGE;
+
+    Cookie ck1 = new Cookie(name, value);
+    NewCookie nck1 = new NewCookie(ck1);
+
+    name = "name_2";
+    value = "value_2";
+    String path = "/acme";
+    String domain = "";
+
+    Cookie ck2 = new Cookie(name, value, path, domain);
+    NewCookie nck2 = new NewCookie(ck2);
+
+    name = "name_3";
+    value = "value_3";
+    path = "";
+    domain = "y.x.foo.com";
+
+    Cookie ck3 = new Cookie(name, value, path, domain);
+    NewCookie nck3 = new NewCookie(ck3);
+
+    List<String> cookies = Arrays.asList(nck1.toString().toLowerCase(),
+        nck2.toString().toLowerCase(), nck3.toString().toLowerCase());
+
+    Response resp = Response.status(status).cookie(nck1, nck2, nck3).build();
+    result = verifyStatus(resp, status);
+    result.append(verifyCookies(resp, cookies));
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: lastModifiedTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:151;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125; JAXRS:JAVADOC:97;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.ResponseBuilder.lastModified(Date).build() verify that correct
+   * status code is returned
+   */
+  @Test
+  public void lastModifiedTest() throws Fault {
+    VerificationResult result;
+    int status = 200;
+    long dt = 123456789;
+    Date date = new Date(dt);
+    HashMap<String, String> expected_map = new HashMap<String, String>();
+    expected_map.put("Last-Modified", "123456789");
+
+    Response resp = Response.status(status).lastModified(date).build();
+    result = verifyStatus(resp, status);
+    result.append(verifyHeaders(resp, expected_map));
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: headerTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:148;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125; JAXRS:JAVADOC:97;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.ResponseBuilder.header(String, Object).build() verify that correct
+   * status code is returned
+   */
+  @Test
+  public void headerTest() throws Fault {
+    VerificationResult result;
+    int status = 200;
+    List<String> type = Arrays.asList("text/plain", "text/html");
+    List<String> encoding = Arrays.asList("gzip", "compress");
+
+    String name = "name_1";
+    String value = "value_1";
+    Cookie ck1 = new Cookie(name, value);
+    NewCookie nck1 = new NewCookie(ck1);
+
+    List<String> cookies = Arrays.asList(nck1.toString().toLowerCase());
+
+    Response resp = Response.status(status)
+        .header(HttpHeaders.CONTENT_ENCODING, encoding.get(0))
+        .header(HttpHeaders.CONTENT_ENCODING, encoding.get(1))
+        .header("Content-Language", "en-US").header("Content-Language", "en-GB")
+        .header("Content-Language", "zh-CN")
+        .header("Cache-Control", "no-transform")
+        .header("Set-Cookie", "name_1=value_1;version=1")
+        .header(HttpHeaders.CONTENT_TYPE, type.get(0))
+        .header(HttpHeaders.CONTENT_TYPE, type.get(1)).build();
+    result = verifyStatus(resp, status);
+    result.append(verifyEncoding(resp, encoding));
+    result.append(verifyLanguage(resp, getLangList()));
+    result.append(verifyContentType(resp, type));
+    result.append(verifyCookies(resp, cookies));
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: cloneTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:139; JAXRS:JAVADOC:141; JAXRS:JAVADOC:143;
+   * JAXRS:JAVADOC:123; JAXRS:JAVADOC:124; JAXRS:JAVADOC:125;
+   * 
+   * @test_Strategy: Create an instance of Response using
+   * Response.ResponseBuilder.clone() verify that correct status code is
+   * returned
+   */
+  @Test
+  public void cloneTest() throws Fault {
+    VerificationResult result;
+    int status = 200;
+    List<String> type = Arrays.asList("text/plain", "text/html");
+    List<String> encoding = Arrays.asList("gzip");
+    List<String> lang = getLangList();
+
+    String name = "name_1";
+    String value = "value_1";
+    Cookie ck1 = new Cookie(name, value);
+    NewCookie nck1 = new NewCookie(ck1);
+
+    List<String> cookies = Arrays.asList(nck1.toString().toLowerCase());
+
+    Response.ResponseBuilder respb1 = Response.status(status)
+        .header("Content-type", "text/plain")
+        .header("Content-type", "text/html").header("Content-Language", "en-US")
+        .header("Content-Language", "en-GB").header("Content-Language", "zh-CN")
+        .header("Cache-Control", "no-transform")
+        .header("Set-Cookie", "name_1=value_1;version=1")
+        .header(HttpHeaders.CONTENT_ENCODING, "gzip");
+    Response.ResponseBuilder respb2;
+    respb2 = respb1.clone();
+
+    Response resp2 = respb2.build();
+    result = verifyStatus(resp2, status);
+    result.append(verifyEncoding(resp2, encoding));
+    result.append(verifyLanguage(resp2, lang));
+    result.append(verifyContentType(resp2, type));
+    result.append(verifyCookies(resp2, cookies));
+
+    String content = "TestOnly";
+    Response resp1 = respb1.entity(content).cookie((NewCookie[]) null).build();
+    result.append(verifyContent(resp1, content));
+    result.append(verifyStatus(resp1, status));
+    result.append(verifyEncoding(resp1, encoding));
+    result.append(verifyLanguage(resp1, lang));
+    result.append(verifyContentType(resp1, type));
+
+    MultivaluedMap<java.lang.String, java.lang.Object> mvp = resp1
+        .getMetadata();
+    if (mvp.containsKey("Set-Cookie")) {
+      result.pass = false;
+      result.message.append("Response contains unexpected Set-Cookie: ")
+          .append(mvp.getFirst("Set-Cookie").toString()).append(newline);
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: statusTest5
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:161;
+   * 
+   * @test_Strategy: Call Response.Status.fromStatusCode(int) verify that
+   * correct Response.Status is returned
+   */
+  @Test
+  public void statusTest5() throws Fault {
+    VerificationResult result = new VerificationResult();
+    Response.Status tmp = null;
+
+    for (int i = 0; i < status_codes.length; i++) {
+      tmp = Response.Status.fromStatusCode(status_codes[i]);
+
+      if (tmp != resp_status[i]) {
+        result.pass = false;
+        result.message.append("fromStatusCode[").append(status_codes[i])
+            .append("] failed with ").append(tmp).append(newline);
+      }
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: getFamilyTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:162;
+   * 
+   * @test_Strategy: Call Response.Status.getFamily() verify that correct
+   * Response.Status.Family is returned
+   */
+  @Test
+  public void getFamilyTest() throws Fault {
+    VerificationResult result = new VerificationResult();
+    Response.Status.Family tmp = null;
+
+    assertTrue(status_family.length == Response.Status.values().length,
+        "Response.Status.values() are unexpected");
+
+    for (int i = 0; i < status_family.length; i++) {
+      tmp = resp_status[i].getFamily();
+
+      if (tmp != status_family[i]) {
+        result.pass = false;
+        result.message.append("getFamily failed with ").append(resp_status[i])
+            .append(" ").append(tmp).append(newline);
+      }
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: statusTest7
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:163;
+   * 
+   * @test_Strategy: Call Response.Status.getStatusCode() verify that correct
+   * status code is returned
+   */
+  @Test
+  public void statusTest7() throws Fault {
+    VerificationResult result = new VerificationResult();
+    int tmp = 0;
+
+    for (int i = 0; i < status_codes.length; i++) {
+      tmp = resp_status[i].getStatusCode();
+
+      if (tmp != status_codes[i]) {
+        result.pass = false;
+        result.message.append("getStatusCode() failed with ")
+            .append(resp_status[i]).append(newline);
+        result.message.append("expecting ").append(status_codes[i])
+            .append(", got ").append(tmp).append(newline);
+      }
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: toStringTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:164;
+   * 
+   * @test_Strategy: Call Response.Status.toString() verify that correct reason
+   * phase is returned
+   */
+  @Test
+  public void toStringTest() throws Fault {
+    VerificationResult result = new VerificationResult();
+    String tmp = null;
+
+    for (int i = 0; i < resp_status.length; i++) {
+      tmp = resp_status[i].toString();
+
+      if (!tmp.equals(status[i])) {
+        result.pass = false;
+        result.message.append("Status.toString() failed with ")
+            .append(resp_status[i]).append(newline);
+        result.message.append("expecting ").append(status[i]).append(", got ")
+            .append(tmp).append(newline);
+      }
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: getReasonPhraseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:301; JAXRS:JAVADOC:166;
+   * 
+   * @test_Strategy: Call Response.Status.getReasonPhrase() verify that correct
+   * reason phase is returned
+   */
+  @Test
+  public void getReasonPhraseTest() throws Fault {
+    VerificationResult result = new VerificationResult();
+    String tmp = null;
+
+    assertTrue(status.length == Response.Status.values().length,
+        "Response.Status.values() are unexpected");
+
+    for (int i = 0; i < resp_status.length; i++) {
+      tmp = resp_status[i].getReasonPhrase();
+
+      if (!tmp.equals(status[i])) {
+        result.pass = false;
+        result.message.append("Status.toString() failed with ")
+            .append(resp_status[i]).append(newline);
+        result.message.append("expecting ").append(status[i]).append(", got ")
+            .append(tmp).append(newline);
+      }
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: statusValueOfTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:165; JAXRS:JAVADOC:166;
+   * 
+   * @test_Strategy: Call Response.Status.valueOf(String) verify that correct
+   * Status is returned
+   */
+  @Test
+  public void statusValueOfTest() throws Fault {
+    VerificationResult result = new VerificationResult();
+    Response.Status tmp = null;
+    for (int i = 0; i < resp_status.length; i++) {
+      try {
+        tmp = Response.Status.valueOf(
+            status[i].replace(" ", "_").replace("-", "_").toUpperCase());
+      } catch (Exception ex) {
+        result.message.append("Exception thrown with status name ")
+            .append(status[i]).append(newline);
+        result.message.append(ex.getMessage());
+        result.pass = false;
+      }
+      if (!tmp.equals(resp_status[i])) {
+        result.pass = false;
+        result.message.append("Status.toString() failed with ")
+            .append(resp_status[i]).append(newline);
+        result.message.append("expecting ").append(resp_status[i])
+            .append(", got ").append(tmp).append(newline);
+      }
+    }
+    logMsg(result);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: statusFamilyValueOfTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:167; JAXRS:JAVADOC:168;
+   * 
+   * @test_Strategy: Call Response.Status.Family.valueOf() verify that correct
+   * Family is returned
+   */
+  @Test
+  public void statusFamilyValueOfTest() throws Fault {
+    Response.Status.Family[] families = Response.Status.Family.values();
+    assertTrue(families.length == status_family_list.length,
+        "Response.Status.Family.values() are unexpected");
+    Arrays.sort(status_family_list);
+    for (int i = 0; i != families.length; i++) {
+      int match = Arrays.binarySearch(status_family_list,
+          Response.Status.Family.valueOf(families[i].name()));
+      assertTrue(match != -1, "Unknown Response Status Family"+ families[i]);
+    }
+  }
+
+  /*
+   * @testName: statusFamilyValuesTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:168;
+   * 
+   * @test_Strategy: Call Response.Status.Family.values() verify that correct
+   * Family is returned
+   */
+  @Test
+  public void statusFamilyValuesTest() throws Fault {
+    Response.Status.Family[] families = Response.Status.Family.values();
+    assertTrue(families.length == status_family_list.length,
+        "Response.Status.Family.values() are unexpected");
+    Arrays.sort(status_family_list);
+    for (int i = 0; i != families.length; i++) {
+      int match = Arrays.binarySearch(status_family_list, families[i]);
+      assertTrue(match != -1, "Unknown Resposne Status Family"+ families[i]);
+    }
+  }
+
+  /*
+   * @testName: acceptedNoArgTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:836;
+   * 
+   * @test_Strategy: Create a new ResponseBuilder with an ACCEPTED status.
+   */
+  @Test
+  public void acceptedNoArgTest() throws Fault {
+    VerificationResult result;
+    Response response = null;
+    response = Response.accepted().build();
+    result = verifyStatus(response, Status.ACCEPTED.getStatusCode());
+    logMsg(result.message);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: acceptedStringTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:837;
+   * 
+   * @test_Strategy: Create a new ResponseBuilder with an ACCEPTED status that
+   * contains a representation. It is the callers responsibility to wrap the
+   * actual entity with GenericEntity if preservation of its generic type is
+   * required.
+   */
+  @Test
+  public void acceptedStringTest() throws Fault {
+    VerificationResult result;
+    String entity = "ENtiTy";
+    Response response = null;
+    response = Response.accepted(entity).build();
+    result = verifyStatus(response, Status.ACCEPTED.getStatusCode());
+    result.append(verifyContent(response, entity));
+    logMsg(result.message);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: acceptedGenericEntityTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:837;
+   * 
+   * @test_Strategy: Create a new ResponseBuilder with an ACCEPTED status that
+   * contains a representation. It is the callers responsibility to wrap the
+   * actual entity with GenericEntity if preservation of its generic type is
+   * required.
+   */
+  @Test
+  public void acceptedGenericEntityTest() throws Fault {
+    VerificationResult result;
+    String entity = "ENtiTy";
+    GenericEntity<String> generic = new GenericEntity<String>(entity,
+        String.class);
+    Response response = Response.accepted(generic).build();
+    result = verifyStatus(response, Status.ACCEPTED.getStatusCode());
+    result.append(verifyContent(response, entity));
+    logMsg(result.message);
+    assertResultTrue(result);
+  }
+
+  /*
+   * @testName: bufferEntityIgnoreNoBackingStreamTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:838;
+   * 
+   * @test_Strategy: In case the response entity instance is not backed by an
+   * unconsumed input stream an invocation of bufferEntity method is ignored and
+   * the method returns false.
+   */
+  @Test
+  public void bufferEntityIgnoreNoBackingStreamTest() throws Fault {
+    Response response = Response.ok().build();
+    boolean result = response.bufferEntity();
+    assertTrue(!result, "#bufferEntity() did not ignore no backing stream");
+    logMsg("#bufferEntity did ignore no backing stream as expected");
+  }
+
+  /*
+   * @testName: bufferEntityThrowsIllegalStateExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:838;
+   * 
+   * @test_Strategy: throws IllegalStateException - in case the response has
+   * been #close() closed.
+   */
+  @Test
+  public void bufferEntityThrowsIllegalStateExceptionTest() throws Fault {
+    Response response = Response.ok().build();
+    response.close();
+    try {
+      response.bufferEntity();
+      fault("buffer entity did not throw IllegalStateException when closed");
+    } catch (IllegalStateException e) {
+      logMsg("#bufferEntity throws IllegalStateException as expected");
+    }
+  }
+
+  /*
+   * @testName: getAllowedMethodsTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:843;
+   * 
+   * @test_Strategy: Get the allowed HTTP methods from the Allow HTTP header.
+   */
+  @Test
+  public void getAllowedMethodsTest() throws Fault {
+    Response response = Response.ok()
+        .header(HttpHeaders.ALLOW, Request.POST.name())
+        .header(HttpHeaders.ALLOW, Request.TRACE.name()).build();
+    Set<String> set = response.getAllowedMethods();
+    String methods = JaxrsUtil.iterableToString(";", set);
+    assertContainsIgnoreCase(methods, Request.POST.name(), Request.POST.name(),
+        "method has not been found");
+    assertContainsIgnoreCase(methods, Request.TRACE.name(),
+        Request.TRACE.name(), "method has not been found");
+    assertTrue(
+        methods.length() < Request.TRACE.name().length()
+            + Request.POST.name().length() + 3,
+        "Request contains some additional methods then expected"+ methods);
+    logMsg("#getAllowedMethods returned expected methods", methods);
+  }
+
+  /*
+   * @testName: getCookiesTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:844;
+   * 
+   * @test_Strategy: Get any new cookies set on the response message.
+   */
+  @Test
+  public void getCookiesTest() throws Fault {
+    NewCookie cookie1 = new NewCookie("c1", "v1");
+    NewCookie cookie2 = new NewCookie("c2", "v2");
+    List<String> cookies = Arrays.asList(cookie1.toString().toLowerCase(),
+        cookie2.toString().toLowerCase());
+    Response response = Response.ok().cookie(cookie1).cookie(cookie2).build();
+    // verifyCookies style test
+    VerificationResult result = verifyCookies(response, cookies);
+    logMsg(result);
+    assertResultTrue(result);
+    // getCookies test
+    Map<String, NewCookie> map = response.getCookies();
+    for (Entry<String, NewCookie> entry : map.entrySet())
+      if (entry.getKey().equals("c1"))
+        assertTrue(entry.getValue().equals(cookie1), cookie1.toString()+
+            "not match"+ entry.getValue());
+      else if (entry.getKey().equals("c2"))
+        assertTrue(entry.getValue().equals(cookie2), cookie2.toString()+
+            "not match"+ entry.getValue());
+      else
+        assertTrue(false, "Got unknown cookie"+ entry.getKey());
+
+    logMsg("#getCookies returned expected cookies");
+  }
+
+  /*
+   * @testName: getCookiesIsImmutableTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:844;
+   * 
+   * @test_Strategy: returns a read-only map of cookie name (String) to Cookie.
+   */
+  @Test
+  public void getCookiesIsImmutableTest() throws Fault {
+    NewCookie cookie1 = new NewCookie("c1", "v1");
+    NewCookie cookie2 = new NewCookie("c2", "v2");
+    Response response = Response.ok().cookie(cookie1).build();
+    // getCookies test
+    Map<String, NewCookie> map;
+    try {
+      map = response.getCookies();
+      map.put("c2", cookie2);
+    } catch (Exception e) {
+      // can throw an exception or nothing or return a copy map
+    }
+    map = response.getCookies();
+    assertTrue(!map.containsKey("c2"), "getCookies is not read-only returned"+
+        map.get("c2"));
+    logMsg("#getCookies is read-only as expected");
+  }
+
+  /*
+   * @testName: getDateTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:845;
+   * 
+   * @test_Strategy: Get message date.
+   */
+  @Test
+  public void getDateTest() throws Fault {
+    Date date = Calendar.getInstance().getTime();
+    Response response = Response.ok().header("Date", date).build();
+
+    Date responseDate = response.getDate();
+    assertTrue(date.equals(responseDate), "Original date"+ date+
+        "and response#getDate()"+ responseDate+ "differs");
+    logMsg("#getDate matches the Date HTTP header");
+  }
+
+  /*
+   * @testName: getDateNotPresentTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:845;
+   * 
+   * @test_Strategy: Get null if not present.
+   */
+  @Test
+  public void getDateNotPresentTest() throws Fault {
+    Response response = Response.ok().build();
+    Date responseDate = response.getDate();
+    assertTrue(responseDate == null, "response#getDate() should be null, was"+
+        responseDate);
+    logMsg("#getDate is null as expected");
+  }
+
+  /*
+   * @testName: getEntityThrowsIllegalStateExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:123;
+   * 
+   * @test_Strategy: if the entity was previously fully consumed as an
+   * InputStream input stream, or if the response has been #close() closed.
+   */
+  @Test
+  public void getEntityThrowsIllegalStateExceptionTest() throws Fault {
+    Response response = Response.ok("entity").build();
+    response.close();
+    try {
+      response.getEntity();
+      fault("No exception has been thrown");
+    } catch (IllegalStateException e) {
+      logMsg("#getEntity throws IllegalStateException as expected", e);
+    }
+  }
+
+  /*
+   * @testName: getEntityTagTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:847;
+   * 
+   * @test_Strategy: Get the entity tag.
+   */
+  @Test
+  public void getEntityTagTest() throws Fault {
+    EntityTag tag = new EntityTag("getEntityTag");
+    Response response = Response.notModified(tag).build();
+    EntityTag responseTag = response.getEntityTag();
+    assertTrue(tag.equals(responseTag), "response#getEntityTag()"+ responseTag+
+        "is unequal to expected EntityTag"+ tag);
+    logMsg("#getEntityTag is", responseTag, "as expected");
+  }
+
+  /*
+   * @testName: getEntityTagNotPresentTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:847;
+   * 
+   * @test_Strategy: Get null if not present.
+   */
+  @Test
+  public void getEntityTagNotPresentTest() throws Fault {
+    Response response = Response.ok().build();
+    EntityTag responseTag = response.getEntityTag();
+    assertTrue(responseTag == null,
+        "response#getEntityTag() should be null, was"+ responseTag);
+    logMsg("#getEntityTag() is null as expected");
+  }
+
+  /*
+   * @testName: getHeadersTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:848;
+   * 
+   * @test_Strategy: Get view of the response headers and their object values.
+   */
+  @Test
+  public void getHeadersTest() throws Fault {
+    CacheControl ccl = new CacheControl();
+    NewCookie cookie = new NewCookie("cookie", "eikooc");
+    String encoding = "gzip";
+    Date date = Calendar.getInstance().getTime();
+
+    Response response = Response.ok().cacheControl(ccl).cookie(cookie)
+        .encoding(encoding).expires(date).language(Locale.CANADA_FRENCH)
+        .build();
+    logMsg("Found following objects:");
+    logMsg((Object[]) JaxrsCommonClient.getMetadata(response.getHeaders()));
+
+    MultivaluedMap<String, Object> headers = response.getHeaders();
+    String header = null;
+
+    header = headers.getFirst(HttpHeaders.CACHE_CONTROL).toString();
+    assertContainsIgnoreCase(header, "no-transform",
+        "Cache-Control:no-transform has not been found");
+
+    header = headers.getFirst(HttpHeaders.SET_COOKIE).toString();
+    assertContainsIgnoreCase(header, "cookie=eikooc",
+        "Set-Cookie:cookie=eikooc has not been found");
+
+    header = headers.getFirst(HttpHeaders.CONTENT_ENCODING).toString();
+    assertContainsIgnoreCase(header, "gzip",
+        "Content-Encoding:gzip has not been found");
+
+    header = headers.getFirst(HttpHeaders.EXPIRES).toString();
+    assertNotNull(header, "Expires has not been found");
+
+    header = headers.getFirst(HttpHeaders.CONTENT_LANGUAGE).toString();
+    assertContainsIgnoreCase(langToString(header),
+        langToString(Locale.CANADA_FRENCH), "Content-Language:",
+        langToString(Locale.CANADA_FRENCH), "has not been found");
+
+    Object noHeader = headers.getFirst("unknown");
+    assertNull(noHeader, "Unknown header has been found", header);
+  }
+
+  /*
+   * @testName: getHeadersIsMutableTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:848;
+   * 
+   * @test_Strategy: Get view of the response headers and their object values.
+   * Changes in the underlying header data are reflected in this view.
+   */
+  @Test
+  public void getHeadersIsMutableTest() throws Fault {
+    String header = "header";
+    Response response = Response.ok().build();
+    MultivaluedMap<String, Object> headers = response.getHeaders();
+    Object value = headers.getFirst(header);
+    assertNull(value, "Unexpected header", header, ":", value);
+    headers.add(header, header);
+    headers = response.getHeaders();
+    value = headers.getFirst(header);
+    assertContainsIgnoreCase(value, header, "Unexpected header value", header,
+        ":", value);
+    logMsg("getHeaders is mutable");
+  }
+
+  /*
+   * @testName: getHeaderStringTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:849;
+   * 
+   * @test_Strategy: Get a message header as a single string value.
+   */
+  @Test
+  public void getHeaderStringTest() throws Fault {
+    CacheControl ccl = new CacheControl();
+    ccl.setNoStore(true);
+    NewCookie cookie = new NewCookie("cookie", "eikooc");
+    String encoding = "gzip";
+    Date date = Calendar.getInstance().getTime();
+
+    Response response = Response.ok().cacheControl(ccl).cookie(cookie)
+        .encoding(encoding).expires(date).language(Locale.CANADA_FRENCH)
+        .build();
+    logMsg("Found following objects:");
+    logMsg((Object[]) JaxrsCommonClient.getMetadata(response.getHeaders()));
+    assertContainsIgnoreCase(
+        response.getHeaderString(HttpHeaders.CACHE_CONTROL), "no-store",
+        "Cache-Control:no-store has not been found");
+    assertContainsIgnoreCase(
+        response.getHeaderString(HttpHeaders.CACHE_CONTROL), "no-transform",
+        "Cache-Control:no-transform has not been found");
+    assertContainsIgnoreCase(response.getHeaderString(HttpHeaders.SET_COOKIE),
+        "cookie=eikooc", "Set-Cookie:cookie=eikooc has not been found");
+    assertContainsIgnoreCase(
+        response.getHeaderString(HttpHeaders.CONTENT_ENCODING), "gzip",
+        "Content-Encoding:gzip has not been found");
+    assertNotNull(response.getHeaderString(HttpHeaders.EXPIRES),
+        "Expires has not been found");
+    assertContainsIgnoreCase(
+        langToString(response.getHeaderString("Content-Language")),
+        langToString(Locale.CANADA_FRENCH), "Content-Language:",
+        langToString(Locale.CANADA_FRENCH), "has not been found");
+    assertNull(response.getHeaderString("unknown"),
+        "Unknown header has been found", response.getHeaderString("unknown"));
+  }
+
+  /*
+   * @testName: getHeaderStringUsingHeaderDelegateTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:849;
+   * 
+   * @test_Strategy: Get a message header as a single string value. Each single
+   * header value is converted to String using a RuntimeDelegate.HeaderDelegate
+   * or using its toString
+   */
+  @Test
+  public void getHeaderStringUsingHeaderDelegateTest() throws Fault {
+    StringBean bean = new StringBean("s3");
+    RuntimeDelegate original = RuntimeDelegate.getInstance();
+    RuntimeDelegate.setInstance(new StringBeanRuntimeDelegate(original));
+    try {
+      Response response = Response.ok().header(bean.get(), bean).build();
+      String header = response.getHeaderString(bean.get());
+      assertContainsIgnoreCase(header, bean.get(), "Header", bean.get(),
+          "has unexpected value", header);
+      logMsg("HeaderDelegate is used for header", bean.get());
+    } finally {
+      RuntimeDelegate.setInstance(original);
+      StringBeanRuntimeDelegate.assertNotStringBeanRuntimeDelegate();
+    }
+  }
+
+  /*
+   * @testName: getHeaderStringUsingToStringTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:849;
+   * 
+   * @test_Strategy: Get a message header as a single string value. Each single
+   * header value is converted to String using a RuntimeDelegate.HeaderDelegate
+   * or using its toString
+   */
+  @Test
+  public void getHeaderStringUsingToStringTest() throws Fault {
+    StringBuilder builder = new StringBuilder("s1");
+    StringBuffer buffer = new StringBuffer("s2");
+    Response response = Response.ok().header(builder.toString(), builder)
+        .header(buffer.toString(), buffer).build();
+    String header = response.getHeaderString(builder.toString());
+    assertContainsIgnoreCase(header, builder.toString(), "Header", builder,
+        "has unexpected value", header);
+
+    header = response.getHeaderString(buffer.toString());
+    assertContainsIgnoreCase(header, buffer.toString(), "Header", builder,
+        "has unexpected value", header);
+
+    logMsg("toString method is used as expected");
+  }
+
+  /*
+   * @testName: getLanguageTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:850;
+   * 
+   * @test_Strategy: Get the language of the message entity.
+   */
+  @Test
+  public void getLanguageTest() throws Fault {
+    Response response = Response.ok().language(Locale.CANADA_FRENCH).build();
+    Locale locale = response.getLanguage();
+    assertTrue(Locale.CANADA_FRENCH.equals(locale), "Locale"+
+        Locale.CANADA_FRENCH+ "does NOT match response#getLocale()"+ locale);
+    logMsg("#getLocale matches the Content-Language HTTP header");
+  }
+
+  /*
+   * @testName: getLanguageNotPresentTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:850;
+   * 
+   * @test_Strategy: Get null if not present.
+   */
+  @Test
+  public void getLanguageNotPresentTest() throws Fault {
+    Response response = Response.ok().build();
+    Locale locale = response.getLanguage();
+    assertTrue(locale == null, "response#getLanguage() should be null, was"+
+        locale);
+    logMsg("#getLanguage() is null as expected");
+  }
+
+  /*
+   * @testName: getLastModifiedTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:851;
+   * 
+   * @test_Strategy: Get the last modified date.
+   */
+  @Test
+  public void getLastModifiedTest() throws Fault {
+    Date date = Calendar.getInstance().getTime();
+    Response response = Response.ok().lastModified(date).build();
+    Date responseDate = response.getLastModified();
+    assertTrue(date.equals(responseDate), "Last Modified date"+ date+
+        "does NOT match response#getLastModified()"+ responseDate);
+    logMsg("#getLastModified matches the Last-Modified HTTP header");
+  }
+
+  /*
+   * @testName: getLastModifiedNotPresentTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:851;
+   * 
+   * @test_Strategy: Get null if not present.
+   */
+  @Test
+  public void getLastModifiedNotPresentTest() throws Fault {
+    Response response = Response.ok().build();
+    Date responseDate = response.getLastModified();
+    assertTrue(responseDate == null,
+        "response#getLastModified() should be null, was"+ responseDate);
+    logMsg("#getLastModified() is null as expected");
+  }
+
+  /*
+   * @testName: getLengthTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:852;
+   * 
+   * @test_Strategy: Get Content-Length value.
+   */
+  @Test
+  public void getLengthTest() throws Fault {
+    Response response = Response.ok("1234567890")
+        .header(HttpHeaders.CONTENT_LENGTH, "10").build();
+    int len = response.getLength();
+    assertTrue(len > 9, "Expected Content-Length > 9"+
+        "does NOT match response#getLength()"+ len);
+    logMsg("#getLength matches expected Content-Length", len);
+  }
+
+  /*
+   * @testName: getLengthNotPresentTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:852;
+   * 
+   * @test_Strategy: In other cases returns -1.
+   */
+  @Test
+  public void getLengthNotPresentTest() throws Fault {
+    Response response = Response.ok().build();
+    int len = response.getLength();
+    assertTrue(len == -1, "Expected Content-Length = -1"+
+        "does NOT match response#getLength()"+ len);
+    logMsg("#getLength matches expected Content-Length", len);
+  }
+
+  /*
+   * @testName: getLinkTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:853;
+   * 
+   * @test_Strategy: Get the link for the relation.
+   */
+  @Test
+  public void getLinkTest() throws Fault {
+    Link link = createLink("path", "getLinkTest");
+    Response response = Response.ok().links(link).build();
+    Link responseLink = response.getLink("getLinkTest");
+    assertTrue(link.equals(responseLink),
+        "#getLink() returned unexpected Link"+ responseLink);
+    logMsg("#getLink matches expected Link");
+  }
+
+  /*
+   * @testName: getLinkNotPresentTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:853;
+   * 
+   * @test_Strategy: returns null if not present.
+   */
+  @Test
+  public void getLinkNotPresentTest() throws Fault {
+    Response response = Response.ok().build();
+    Link responseLink = response.getLink("getLinkTest");
+    assertTrue(responseLink == null, "#getLink() returned unexpected Link"+
+        responseLink);
+    logMsg("#getLink return null as expected");
+  }
+
+  /*
+   * @testName: getLinkBuilderForTheRelationTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:854;
+   * 
+   * @test_Strategy: Convenience method that returns a Link.Builder for the
+   * relation.
+   */
+  @Test
+  public void getLinkBuilderForTheRelationTest() throws Fault {
+    String rel = "anyrelation";
+    Response response = Response.ok().link("http://abc.com/b/", rel).build();
+    Link builderLink = response.getLinkBuilder("anyrelation").build();
+    response = Response.ok().links(builderLink).build();
+    Link responseLink = response.getLink("anyrelation");
+    assertNotNull(responseLink, "#getLinkBuilder('relation') returned null");
+    logMsg("#getLinkBuilder creates correct Link for given relation");
+  }
+
+  /*
+   * @testName: getLinkBuilderForTheNotPresentRelationTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:854;
+   * 
+   * @test_Strategy: returns null if not present.
+   */
+  @Test
+  public void getLinkBuilderForTheNotPresentRelationTest() throws Fault {
+    Response response = Response.ok().build();
+    Builder builder = response.getLinkBuilder("anyrelation");
+    assertTrue(builder == null,
+        "#getLinkBuilder('relation') returned unexpected builder"+ builder);
+    logMsg("#getLinkBuilder returned null as expected");
+  }
+
+  /*
+   * @testName: getLinksTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:855;
+   * 
+   * @test_Strategy: Get the links attached to the message as header.
+   */
+  @Test
+  public void getLinksTest() throws Fault {
+    Link link1 = createLink("path1", "rel1");
+    Link link2 = createLink("path2", "rel2");
+    Response response = Response.ok().links(link1, link2).build();
+    Set<Link> responseLinks = response.getLinks();
+    assertEqualsInt(responseLinks.size(), 2,
+        "#getLinks() returned set of unexpected size", responseLinks.size());
+    assertTrue(responseLinks.contains(link1), "#getLinks does not contain"+
+        link1);
+    assertTrue(responseLinks.contains(link2), "#getLinks does not contain"+
+        link2);
+    logMsg("#getLinks contains expected links");
+  }
+
+  /*
+   * @testName: getLinksIsNotNullTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:855;
+   * 
+   * @test_Strategy: Does not return null.
+   */
+  @Test
+  public void getLinksIsNotNullTest() throws Fault {
+    Response response = Response.ok().build();
+    Set<Link> responseLinks = response.getLinks();
+    assertTrue(responseLinks != null, "#getLinks() returned null!");
+    assertTrue(responseLinks.size() == 0,
+        "#getLinks() returned non-empty map!");
+    logMsg("#getLinks contains no links as expected");
+  }
+
+  /*
+   * @testName: getLocationTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:856;
+   * 
+   * @test_Strategy: Get the location.
+   */
+  @Test
+  public void getLocationTest() throws Fault {
+    URI location = createUri("path");
+    Response response = Response.ok().location(location).build();
+    URI responseLocation = response.getLocation();
+    assertTrue(responseLocation.equals(location), "#getLocation()"+
+        responseLocation+ "differs from expected"+ location);
+    logMsg("#getLocation contains expected location");
+  }
+
+  /*
+   * @testName: getLocationNotPresentTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:856;
+   * 
+   * @test_Strategy: Get null when no present.
+   */
+  @Test
+  public void getLocationNotPresentTest() throws Fault {
+    Response response = Response.ok().build();
+    URI responseLocation = response.getLocation();
+    assertTrue(responseLocation == null, "#getLocation()"+ responseLocation+
+        "should be null");
+    logMsg("#getLocation returns null as expected");
+  }
+
+  /*
+   * @testName: getMediaTypeTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:857;
+   * 
+   * @test_Strategy: Get the media type of the message entity.
+   */
+  @Test
+  public void getMediaTypeTest() throws Fault {
+    Response response = Response.ok().type(MediaType.APPLICATION_ATOM_XML)
+        .build();
+    MediaType responseMedia = response.getMediaType();
+    assertTrue(MediaType.APPLICATION_ATOM_XML_TYPE.equals(responseMedia),
+        "#getMediaType()"+ responseMedia+ "differs from expected"+
+        MediaType.APPLICATION_ATOM_XML);
+    logMsg("#getMediaType returned expected MediaType");
+  }
+
+  /*
+   * @testName: getMediaTypeNoMediaTypeTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:857;
+   * 
+   * @test_Strategy: null if there is no response entity.
+   */
+  @Test
+  public void getMediaTypeNoMediaTypeTest() throws Fault {
+    Response response = Response.ok().build();
+    MediaType responseMedia = response.getMediaType();
+    assertTrue(responseMedia == null, "#getMediaType()"+ responseMedia+
+        "should be null");
+    logMsg("#getMediaType returned null as expected");
+  }
+
+  /*
+   * @testName: getStatusInfoTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:858;
+   * 
+   * @test_Strategy: Get the complete status information associated with the
+   * response.
+   */
+  @Test
+  public void getStatusInfoTest() throws Fault {
+    for (Status status : Status.values()) {
+      Response response = Response.status(status).build();
+      StatusType info = response.getStatusInfo();
+      assertTrue(info.getStatusCode() == status.getStatusCode(),
+          "#getStatusInfo returned unexpected value"+ info);
+    }
+    logMsg("#getStatusInfo returned expected StatusTypes");
+  }
+
+  /*
+   * @testName: getStringHeadersUsingToStringTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:859;
+   * 
+   * @test_Strategy: Get view of the response headers and their string values.
+   * Each single header value is converted to String using a
+   * RuntimeDelegate.HeaderDelegate or using its toString
+   */
+  @Test
+  public void getStringHeadersUsingToStringTest() throws Fault {
+    RuntimeDelegate original = RuntimeDelegate.getInstance();
+    RuntimeDelegate.setInstance(new StringBeanRuntimeDelegate(original));
+    try {
+      StringBuilder builder = new StringBuilder("s1");
+      StringBuffer buffer = new StringBuffer("s2");
+      StringBean bean = new StringBean("s3");
+      Response response = Response.ok().header(builder.toString(), builder)
+          .header(buffer.toString(), buffer).header(bean.get(), bean).build();
+      MultivaluedMap<String, String> headers = response.getStringHeaders();
+      String header = headers.getFirst(builder.toString());
+      assertContainsIgnoreCase(header, builder.toString(), "Header", builder,
+          "has unexpected value", header);
+
+      header = headers.getFirst(buffer.toString());
+      assertContainsIgnoreCase(header, buffer.toString(), "Header", builder,
+          "has unexpected value", header);
+
+      logMsg("#getStringHeaders contains expected values",
+          JaxrsUtil.iterableToString(",", headers.entrySet()));
+    } finally {
+      RuntimeDelegate.setInstance(original);
+      StringBeanRuntimeDelegate.assertNotStringBeanRuntimeDelegate();
+    }
+  }
+
+  /*
+   * @testName: getStringHeadersUsingHeaderDelegateTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:859;
+   * 
+   * @test_Strategy: Get view of the response headers and their string values.
+   * Each single header value is converted to String using a
+   * RuntimeDelegate.HeaderDelegate or using its toString
+   */
+  @Test
+  public void getStringHeadersUsingHeaderDelegateTest() throws Fault {
+    RuntimeDelegate original = RuntimeDelegate.getInstance();
+    RuntimeDelegate.setInstance(new StringBeanRuntimeDelegate(original));
+    try {
+      StringBuilder builder = new StringBuilder("s1");
+      StringBuffer buffer = new StringBuffer("s2");
+      StringBean bean = new StringBean("s3");
+      Response response = Response.ok().header(builder.toString(), builder)
+          .header(buffer.toString(), buffer).header(bean.get(), bean).build();
+      MultivaluedMap<String, String> headers = response.getStringHeaders();
+      String header = headers.getFirst(bean.get());
+      assertContainsIgnoreCase(bean.get(), header, "Header", bean.get(),
+          "has unexpected value", header);
+
+      logMsg("#getStringHeaders contains expected values",
+          JaxrsUtil.iterableToString(",", headers.entrySet()));
+    } finally {
+      RuntimeDelegate.setInstance(original);
+      StringBeanRuntimeDelegate.assertNotStringBeanRuntimeDelegate();
+    }
+  }
+
+  /*
+   * @testName: hasEntityWhenEntityTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:860;
+   * 
+   * @test_Strategy: Check if there is an entity available in the response.
+   */
+  @Test
+  public void hasEntityWhenEntityTest() throws Fault {
+    Response response = Response.ok("entity").build();
+    assertTrue(response.hasEntity(), "#hasEntity did not found the entity");
+    logMsg("#hasEntity found the entity as expected");
+  }
+
+  /*
+   * @testName: hasEntityWhenNoEntityTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:860;
+   * 
+   * @test_Strategy: Check if there is an entity available in the response.
+   */
+  @Test
+  public void hasEntityWhenNoEntityTest() throws Fault {
+    Response response = Response.ok().build();
+    assertTrue(!response.hasEntity(), "#hasEntity did found the entity");
+    logMsg("#hasEntity has not found any entity as expected");
+  }
+
+  /*
+   * @testName: hasEntityThrowsIllegalStateExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:860;
+   * 
+   * @test_Strategy: throws java.lang.IllegalStateException - in case the
+   * response has been closed.
+   */
+  @Test
+  public void hasEntityThrowsIllegalStateExceptionTest() throws Fault {
+    Response response = Response.ok().build();
+    response.close();
+    try {
+      response.hasEntity();
+      fault("No exception has been thrown");
+    } catch (IllegalStateException e) {
+      logMsg("IllegalStateException has been thrown as expected");
+    }
+
+  }
+
+  /*
+   * @testName: hasLinkWhenLinkTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:862;
+   * 
+   * @test_Strategy: Check if link for relation exists.
+   */
+  @Test
+  public void hasLinkWhenLinkTest() throws Fault {
+    Link link = createLink("path", "rel");
+    Response response = Response.ok().links(link).build();
+    assertTrue(response.hasLink("rel"), "#hasLink did not found a Link");
+    logMsg("#hasEntity found the Link as expected");
+  }
+
+  /*
+   * @testName: hasLinkWhenNoLinkTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:862;
+   * 
+   * @test_Strategy: Check if link for relation exists.
+   */
+  @Test
+  public void hasLinkWhenNoLinkTest() throws Fault {
+    Response response = Response.ok().build();
+    assertTrue(!response.hasLink("rel"), "#has Link did found some Link");
+    logMsg("#hasLink has not found any Link as expected");
+  }
+
+  // /////////////////////////////////////////////////////////////////////////
+
+  protected VerificationResult verifyContent(Response response,
+      String content) {
+    VerificationResult result = new VerificationResult();
+    if ((content == null) || (content == "")) {
+      if (!(response.getEntity() == null)
+          || (response.getEntity().equals(""))) {
+        result.pass = false;
+        result.message.append(indent)
+            .append("Entity verification failed: expecting no content, got ")
+            .append(response.getEntity()).append(newline);
+      }
+    } else if (!content.equals(response.getEntity())) {
+      result.pass = false;
+      result.message.append(indent)
+          .append("Entity verification failed: expecting ").append(content)
+          .append(", got ").append(response.getEntity()).append(newline);
+    } else {
+      result.message.append(indent)
+          .append("Correct content found in Response: ")
+          .append(response.getEntity()).append(newline);
+    }
+    result.message.append(newline);
+    return result;
+  }
+
+  protected VerificationResult verifyStatus(Response response, int status) {
+    VerificationResult result = new VerificationResult();
+    if (response.getStatus() != status) {
+      result.pass = false;
+      result.message.append(indent)
+          .append("Status code verification failed: expecting ").append(status)
+          .append(", got ").append(response.getStatus()).append(newline);
+    } else {
+      result.message.append(indent).append("Correct status found in Response: ")
+          .append(status).append(newline);
+    }
+    result.message.append(newline);
+    return result;
+  }
+
+  protected VerificationResult verifyHeaders(Response response,
+      HashMap<String, String> expected) {
+    MultivaluedMap<java.lang.String, java.lang.Object> headers = response
+        .getMetadata();
+    VerificationResult result = new VerificationResult();
+    result.message.append("========== Verifying a Response with Map: ")
+        .append(newline);
+    for (String key_actual : headers.keySet()) {
+      result.message.append(indent).append("Response contains key: ")
+          .append(key_actual).append(newline);
+    }
+    result.message.append(indent)
+        .append("Verifying the following keys in Response:").append(newline);
+    String actual;
+
+    for (Entry<String, String> entry : expected.entrySet()) {
+      String key = entry.getKey();
+      String value = entry.getValue();
+
+      if (!headers.containsKey(key)) {
+        result.pass = false;
+        result.message.append(indent).append(indent).append("Key: ").append(key)
+            .append(" is not found in Response;").append(newline);
+      } else if (key.equalsIgnoreCase("last-modified")) {
+        result.message.append(indent).append(indent)
+            .append("Key Last-Modified is found in response").append(newline);
+      } else {
+        actual = headers.getFirst(key).toString().toLowerCase();
+
+        if (actual.startsWith("\"") && actual.endsWith("\""))
+          actual = actual.substring(1, actual.length() - 1);
+
+        if (!actual.equalsIgnoreCase(value)) {
+          result.pass = false;
+          result.message.append(indent).append(indent);
+          result.message.append("Key: ").append(key);
+          result.message.append(" found in Response, but with different value;")
+              .append(newline);
+          result.message.append(indent).append(indent).append("Expecting ")
+              .append(value).append("; got ").append(headers.getFirst(key))
+              .append(newline);
+        }
+        result.message.append(indent).append(indent).append("Processed key ")
+            .append(key).append(" with expected value ").append(value)
+            .append(newline);
+      }
+    }
+    result.message.append(newline);
+    return result;
+  }
+
+  protected VerificationResult verifyEncoding(Response response,
+      List<String> encoding) {
+    VerificationResult result = new VerificationResult();
+    List<Object> enc = response.getHeaders().get(HttpHeaders.CONTENT_ENCODING);
+    if (enc == null) {
+      result.pass = false;
+      result.message.append(HttpHeaders.CONTENT_ENCODING)
+          .append(" headers is null").append(newline);
+      result.message.append("Headers :").append(response.getHeaders())
+          .append(newline);
+    } else
+      for (Object e : enc)
+        if (!encoding.contains(e.toString().toLowerCase())) {
+          result.pass = false;
+          result.message.append(indent).append(indent).append("Encoding ")
+              .append(e).append(" was not found in headers")
+              .append(response.getHeaders()).append(newline);
+        } else
+          result.message.append(indent).append("Encoding ").append(e)
+              .append(" was found").append(newline);
+    result.message.append(newline);
+    return result;
+  }
+
+  protected VerificationResult verifyLanguage(Response response,
+      List<String> languages) {
+    VerificationResult result = new VerificationResult();
+    List<Object> responseLangs = response.getHeaders()
+        .get(HttpHeaders.CONTENT_LANGUAGE); // one only
+    if (responseLangs == null) {
+      result.pass = false;
+      result.message.append(HttpHeaders.CONTENT_LANGUAGE)
+          .append(" headers is null").append(newline);
+      result.message.append("Headers :").append(response.getHeaders())
+          .append(newline);
+    } else {
+      String lang = langToString(JaxrsUtil.iterableToString(" ", languages))
+          .toLowerCase();
+      for (Object responseLang : responseLangs)
+        if (!lang.contains(langToString(responseLang).toLowerCase())) {
+          result.pass = false;
+          result.message.append(indent).append(indent)
+              .append("language test failed: ").append(responseLang)
+              .append(" is not expected in Response")
+              .append(response.getHeaders()).append(newline);
+          for (String tt : languages) {
+            result.message.append(indent).append(indent)
+                .append("Expecting Content-Language ").append(tt)
+                .append(newline);
+          }
+        } else
+          result.message.append(indent).append("Content Language ").append(lang)
+              .append(" was found").append(newline);
+    }
+    result.message.append(newline);
+    return result;
+  }
+
+  protected VerificationResult verifyContentType(Response response,
+      List<String> type) {
+    VerificationResult result = new VerificationResult();
+    List<Object> enc = response.getHeaders().get(HttpHeaders.CONTENT_TYPE);
+    if (enc == null) {
+      result.pass = false;
+      result.message.append(HttpHeaders.CONTENT_TYPE).append(" headers is null")
+          .append(newline);
+      result.message.append("Headers :").append(response.getHeaders())
+          .append(newline);
+    } else
+      for (Object e : enc)
+        if (!type.contains(e.toString().toLowerCase())) {
+          result.pass = false;
+          result.message.append(indent).append(indent).append("Content-Type ")
+              .append(e).append(" was not found in headers")
+              .append(response.getHeaders()).append(newline);
+        } else
+          result.message.append(indent).append("Content Type ").append(e)
+              .append(" was found").append(newline);
+    result.message.append(newline);
+    return result;
+  }
+
+  protected VerificationResult verifyVary(Response response, List<String> var) {
+    VerificationResult result = new VerificationResult();
+    if (var != null)
+      for (Entry<String, List<Object>> entry : response.getMetadata()
+          .entrySet())
+        if (entry.getKey().equalsIgnoreCase("Vary"))
+          for (String value : var) {
+            String actual = entry.getValue().toString().toLowerCase();
+            if (actual.indexOf(value.toLowerCase()) < 0) {
+              result.pass = false;
+              result.message.append(indent).append(indent)
+                  .append("Expected header ").append(value)
+                  .append(" not set in Vary.").append(newline);
+            } else {
+              result.message.append(indent).append(indent)
+                  .append("Found expected header ").append(value).append(".")
+                  .append(newline);
+            }
+          }
+    result.message.append(newline);
+    return result;
+  }
+
+  protected VerificationResult verifyCacheControl(Response response,
+      List<String> ccl) {
+    VerificationResult result = new VerificationResult();
+    if (ccl != null) {
+      for (String tt : ccl)
+        result.message.append("Expecting Cache-Control ").append(tt)
+            .append(newline);
+      for (Entry<String, List<Object>> entry : response.getMetadata()
+          .entrySet())
+        if (entry.getKey().equalsIgnoreCase("Cache-Control"))
+          for (Object all_ccl : entry.getValue())
+            for (String cc : ccl)
+              if (!(all_ccl.toString().toLowerCase()
+                  .indexOf(cc.toLowerCase()) > -1)) {
+                result.pass = false;
+                result.message.append(indent).append(indent)
+                    .append("Cache-Control test failed: ").append(cc)
+                    .append(" is not found in Response.").append(newline);
+              }
+    }
+    result.message.append(newline);
+    return result;
+  }
+
+  protected VerificationResult verifyCookies(Response response,
+      List<String> cookies) {
+    VerificationResult result = new VerificationResult();
+    if (cookies != null) {
+      for (String tt : cookies)
+        result.message.append(indent).append(indent)
+            .append("Expecting Set-Cookie").append(tt).append(newline);
+      for (Entry<String, List<Object>> entry : response.getMetadata()
+          .entrySet()) {
+        if (entry.getKey().equalsIgnoreCase("Set-Cookie"))
+          for (Object nck_actual : entry.getValue()) {
+            result.message.append(indent).append(indent).append("Processing ")
+                .append(nck_actual.toString()).append(newline);
+            if (!cookies.contains(
+                nck_actual.toString().toLowerCase().replace(" ", ""))) {
+              result.pass = false;
+              result.message.append(indent).append(indent)
+                  .append("Set-Cookie test failed: ").append(nck_actual)
+                  .append(" is not expected in Response.").append(newline);
+            } else {
+              result.message.append(indent).append(indent)
+                  .append("Expected Set-Cookie: ").append(nck_actual)
+                  .append(" is found in Response.").append(newline);
+            }
+          }
+      }
+    }
+    result.message.append(newline);
+    return result;
+  }
+
+   protected static void assertResultTrue(VerificationResult result)   {
+    assertTrue(result.pass, "At least one assertion failed");
+  }
+
+  protected static List<String> getLangList() {
+    return Arrays.asList("en-US", "en-GB", "zh-CN");
+  }
+
+  protected static List<Variant> getVariantList(List<String> encoding,
+      MediaType... mt) {
+    return Variant.VariantListBuilder.newInstance().mediaTypes(mt)
+        .languages(new Locale("en", "US"), new Locale("en", "GB"),
+            new Locale("zh", "CN"))
+        .encodings(encoding.toArray(new String[0])).add().build();
+  }
+
+  protected static String langToString(Object object) {
+    Locale locale = null;
+    if (object instanceof List)
+      object = ((List<?>) object).iterator().next();
+    if (object instanceof Locale)
+      locale = (Locale) object;
+    String value = locale == null ? object.toString() : locale.toString();
+    return value.replace("_", "-");
+  }
+
+  protected static Link createLink(String path, String rel) throws Fault {
+    return Link.fromUri(createUri(path)).rel(rel).build();
+  }
+
+  protected static URI createUri(String path) throws Fault {
+    URI uri;
+    try {
+      uri = new URI("http://localhost.tck:888/url404/" + path);
+    } catch (URISyntaxException e) {
+      throw new Fault(e);
+    }
+    return uri;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/responseclient/VerificationResult.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/responseclient/VerificationResult.java
new file mode 100644
index 0000000..c2fb11a
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/responseclient/VerificationResult.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.api.rs.core.responseclient;
+
+/**
+ * Verification holder structure
+ */
+public class VerificationResult {
+  public boolean pass;
+
+  public StringBuilder message;
+
+  public VerificationResult() {
+    pass = true;
+    message = new StringBuilder();
+  }
+
+  public VerificationResult(VerificationResult result) {
+    this.pass = result.pass;
+    this.message = new StringBuilder().append(message);
+  }
+
+  public VerificationResult append(VerificationResult result) {
+    this.pass &= result.pass;
+    this.message.append(result.message).append("\n");
+    return this;
+  }
+
+  @Override
+  public String toString() {
+    return message.toString();
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/uribuilder/JAXRSClientIT.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/uribuilder/JAXRSClientIT.java
new file mode 100644
index 0000000..32e02c0
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/uribuilder/JAXRSClientIT.java
@@ -0,0 +1,3338 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.api.rs.core.uribuilder;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+
+import jakarta.ws.rs.tck.common.JAXRSCommonClient;
+
+import jakarta.ws.rs.core.Link;
+import jakarta.ws.rs.core.UriBuilder;
+import jakarta.ws.rs.core.UriBuilderException;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.AfterEach;
+
+
+/*
+ * @class.setup_props: webServerHost;
+ *                     webServerPort;
+ */
+public class JAXRSClientIT extends JAXRSCommonClient {
+
+  private static final long serialVersionUID = 1814450070599603168L;
+
+  private static final String LOCALHOST = "http://localhost:8080";
+
+  private static final String EXPECTED_PATH = "path-rootless/test2/x%25yz//path-absolute/test1/fred@example.com/x%25yz";
+
+  private static final String ENCODED_EXPECTED_PATH = "path-rootless%2Ftest2/x%25yz/%2Fpath-absolute%2F%2525test1/fred@example.com/x%25yz";
+
+  StringBuilder sb;
+
+  boolean pass = true;
+
+  URI uri;
+
+  public JAXRSClientIT() {
+    setContextRoot("/jaxrs_rs.core_uribuilder_web");
+    pass = true;
+    sb = new StringBuilder();
+  }
+
+  @BeforeEach
+  void logStartTest(TestInfo testInfo) {
+    TestUtil.logMsg("STARTING TEST : "+testInfo.getDisplayName());
+  }
+
+  @AfterEach
+  void logFinishTest(TestInfo testInfo) {
+    TestUtil.logMsg("FINISHED TEST : "+testInfo.getDisplayName());
+  }
+
+  /*
+   * @testName: buildTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:176; JAXRS:JAVADOC:190;
+   * 
+   * @test_Strategy: Create an Uri instance using
+   * UriBuilder.fromPath(String).build(String)
+   */
+  @Test
+  public void buildTest1() throws Fault {
+    String value = "test1#test2";
+    String expected_value = "test1%23test2";
+
+    try {
+      uri = UriBuilder.fromPath("{arg1}").build(value);
+      gotExpectedPass(uri.toString(), expected_value);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: buildTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:177;
+   * 
+   * @test_Strategy: Create an Uri instance using
+   * UriBuilder.fromPath(String).build(null); Verify that
+   * IllegalArgumentException is thrown.
+   */
+  @Test
+  public void buildTest2() throws Fault {
+    String value = null;
+
+    try {
+      UriBuilder.fromPath("{arg1}").build(value);
+      pass = false;
+      sb.append("Expected IllegalArgumentException not thrown" + newline);
+
+    } catch (IllegalArgumentException ilex) {
+      sb.append("Expected IllegalArgumentException thrown");
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: fragmentTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:176; JAXRS:JAVADOC:189; JAXRS:JAVADOC:190;
+   * 
+   * @test_Strategy: Create an Uri instance using
+   * UriBuilder.fromPath(String).fragment(String).build()
+   */
+  @Test
+  public void fragmentTest1() throws Fault {
+    String expected_value = "test#xyz";
+
+    try {
+      uri = UriBuilder.fromPath("test").fragment("xyz").build();
+      gotExpectedPass(uri.toString(), expected_value);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: buildFromMapTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:185;
+   * 
+   * @test_Strategy: Create an URI instance using UriBuilder.buildFromMap(Map);
+   * Verify % is encoded; and all parameter are replaced by values supplied in
+   * Map.
+   */
+  @Test
+  public void buildFromMapTest1() throws Fault {
+    Map<String, String> maps = new HashMap<String, String>();
+    maps.put("x", "x%yz");
+    maps.put("y", "/path-absolute/%25test1");
+    maps.put("z", "fred@example.com");
+    maps.put("w", "path-rootless/test2");
+
+    try {
+      uri = UriBuilder.fromPath("").path("{w}/{x}/{y}/{z}/{x}")
+          .buildFromMap(maps);
+      gotExpectedPass(uri.getRawPath(), ENCODED_EXPECTED_PATH);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage() + newline);
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: buildFromMapTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:185;
+   * 
+   * @test_Strategy: Create an URI instance using UriBuilder.buildFromMap(Map);
+   * Verify % is encoded; and all parameter are replaced by values supplied in
+   * Map.
+   */
+  @Test
+  public void buildFromMapTest2() throws Fault {
+    Map<String, String> maps = new HashMap<String, String>();
+    maps.put("x", "x%yz");
+    maps.put("y", "/path-absolute/%25test1");
+    maps.put("z", "fred@example.com");
+    maps.put("w", "path-rootless/test2");
+    maps.put("u", "extra");
+
+    try {
+      uri = UriBuilder.fromPath("").path("{w}/{x}/{y}/{z}/{x}")
+          .buildFromMap(maps);
+      gotExpectedPass(uri.getRawPath(), ENCODED_EXPECTED_PATH);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage() + newline);
+    }
+
+    assertPassAndLog();
+  }
+
+
+  /*
+   * @testName: buildFromMapTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:185;
+   * 
+   * @test_Strategy: Create an URI instance using UriBuilder.buildFromMap(Map);
+   * Verify IllegalArgumentException is thrown when one parameter value is null.
+   */
+  @Test
+  public void buildFromMapTest3() throws Fault {
+    Map<String, String> maps = new HashMap<String, String>();
+    maps.put("x", null);
+    maps.put("y", "/path-absolute/test1");
+    maps.put("z", "fred@example.com");
+    maps.put("w", "path-rootless/test2");
+    maps.put("u", "extra");
+
+    try {
+      UriBuilder.fromPath("").path("{w}/{x}/{y}/{z}/{x}").buildFromMap(maps);
+      throw new Fault(
+          "Test Failed: expected IllegalArgumentException not thrown");
+    } catch (IllegalArgumentException ex) {
+      TestUtil.logTrace("Test passed: expected TestUtil.logTrace( thrown");
+    }
+  }
+
+  /*
+   * @testName: buildFromMapTest4
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:185;
+   * 
+   * @test_Strategy: Create an URI instance using UriBuilder.buildFromMap(Map);
+   * Verify IllegalArgumentException is thrown when one parameter value is null.
+   */
+  @Test
+  public void buildFromMapTest4() throws Fault {
+    Map<String, String> maps = new HashMap<String, String>();
+    maps.put("x", "x%yz");
+    maps.put("y", "/path-absolute/test1");
+    maps.put("z", "fred@example.com");
+    maps.put("w", "path-rootless/test2");
+    maps.put("u", "extra");
+
+    try {
+      UriBuilder.fromPath("").path("{w}/{v}/{x}/{y}/{z}/{x}")
+          .buildFromMap(maps);
+      throw new Fault(
+          "Test Failed: expected IllegalArgumentException not thrown");
+    } catch (IllegalArgumentException ex) {
+      TestUtil.logTrace("Test passed: expected TestUtil.logTrace( thrown");
+    }
+  }
+
+  /*
+   * @testName: buildFromMapTest5
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:185;
+   * 
+   * @test_Strategy: Create multiple URI instances from the same UriBuilder
+   * instance using the UriBuilder.buildFromMap(Map); Verify that the builder is
+   * not affected.
+   */
+  @Test
+  public void buildFromMapTest5() throws Fault {
+    UriBuilder ub;
+
+    Map<String, String> maps = new HashMap<String, String>();
+    maps.put("x", "x%yz");
+    maps.put("y", "/path-absolute/%25test1");
+    maps.put("z", "fred@example.com");
+    maps.put("w", "path-rootless/test2");
+
+    Map<String, String> maps1 = new HashMap<String, String>();
+    maps1.put("x", "x%20yz");
+    maps1.put("y", "/path-absolute/test1");
+    maps1.put("z", "fred@example.com");
+    maps1.put("w", "path-rootless/test2");
+
+    Map<String, String> maps2 = new HashMap<String, String>();
+    maps2.put("x", "x%yz");
+    maps2.put("y", "/path-absolute/%25test1");
+    maps2.put("z", "fred@example.com");
+    maps2.put("w", "path-rootless/test2");
+    maps2.put("v", "xyz");
+
+    String expected_path_1 = "path-rootless%2Ftest2/x%2520yz/%2Fpath-absolute%2Ftest1/fred@example.com/x%2520yz";
+
+    try {
+      ub = UriBuilder.fromPath("").path("{w}/{x}/{y}/{z}/{x}");
+
+      uri = ub.buildFromMap(maps);
+      gotExpectedPass(uri.getRawPath(), ENCODED_EXPECTED_PATH);
+
+      uri = ub.buildFromMap(maps1);
+      gotExpectedPass(uri.getRawPath(), expected_path_1);
+
+      uri = ub.buildFromMap(maps2);
+      gotExpectedPass(uri.getRawPath(), ENCODED_EXPECTED_PATH);
+    } catch (Throwable ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage() + newline);
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: buildFromEncodedMapTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:182;
+   * 
+   * @test_Strategy: Create an URI instance using
+   * UriBuilder.buildFromEncodedMap(Map); Verify % is encoded when needed; and
+   * all parameter are replaced by values supplied in Map.
+   */
+  @Test
+  public void buildFromEncodedMapTest1() throws Fault {
+    Map<String, String> maps = new HashMap<String, String>();
+    maps.put("x", "x%20yz");
+    maps.put("y", "/path-absolute/%test1");
+    maps.put("z", "fred@example.com");
+    maps.put("w", "path-rootless/test2");
+
+    String expected_path = "path-rootless/test2/x%20yz//path-absolute/%25test1/fred@example.com/x%20yz";
+
+    try {
+      uri = UriBuilder.fromPath("").path("{w}/{x}/{y}/{z}/{x}")
+          .buildFromEncodedMap(maps);
+      gotExpectedPass(uri.getRawPath(), expected_path);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage() + newline);
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: buildFromEncodedMapTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:182;
+   * 
+   * @test_Strategy: Create an URI instance using
+   * UriBuilder.buildFromEncodedMap(Map); Verify % is encoded; and all parameter
+   * are replaced by values supplied in Map.
+   */
+  @Test
+  public void buildFromEncodedMapTest2() throws Fault {
+    Map<String, String> maps = new HashMap<String, String>();
+    maps.put("x", "x%yz");
+    maps.put("y", "/path-absolute/test1");
+    maps.put("z", "fred@example.com");
+    maps.put("w", "path-rootless/test2");
+    maps.put("u", "extra");
+
+    try {
+      uri = UriBuilder.fromPath("").path("{w}/{x}/{y}/{z}/{x}")
+          .buildFromEncodedMap(maps);
+      gotExpectedPass(uri.getRawPath(), EXPECTED_PATH);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage() + newline);
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: buildFromEncodedMapTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:183;
+   * 
+   * @test_Strategy: Create an URI instance using
+   * UriBuilder.buildFromEncodedMap(Map); Verify IllegalArgumentException is
+   * thrown when one parameter value is null.
+   */
+  @Test
+  public void buildFromEncodedMapTest3() throws Fault {
+    Map<String, String> maps = new HashMap<String, String>();
+    maps.put("x", null);
+    maps.put("y", "/path-absolute/test1");
+    maps.put("z", "fred@example.com");
+    maps.put("w", "path-rootless/test2");
+    maps.put("u", "extra");
+
+    try {
+      UriBuilder.fromPath("").path("{w}/{x}/{y}/{z}/{x}")
+          .buildFromEncodedMap(maps);
+      throw new Fault(
+          "Test Failed: expected IllegalArgumentException not thrown");
+    } catch (IllegalArgumentException ex) {
+      TestUtil.logTrace("Test passed: expected TestUtil.logTrace( thrown");
+    }
+  }
+
+  /*
+   * @testName: buildFromEncodedMapTest4
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:183;
+   * 
+   * @test_Strategy: Create an URI instance using
+   * UriBuilder.buildFromEncodedMap(Map); Verify IllegalArgumentException is
+   * thrown when one parameter value is null.
+   */
+  @Test
+  public void buildFromEncodedMapTest4() throws Fault {
+    Map<String, String> maps = new HashMap<String, String>();
+    maps.put("x", "x%yz");
+    maps.put("y", "/path-absolute/test1");
+    maps.put("z", "fred@example.com");
+    maps.put("w", "path-rootless/test2");
+    maps.put("u", "extra");
+
+    try {
+      UriBuilder.fromPath("").path("{w}/{v}/{x}/{y}/{z}/{x}")
+          .buildFromEncodedMap(maps);
+      throw new Fault(
+          "Test Failed: expected IllegalArgumentException not thrown");
+    } catch (IllegalArgumentException ex) {
+      TestUtil.logTrace("Test passed: expected TestUtil.logTrace( thrown");
+    }
+  }
+
+  /*
+   * @testName: buildFromEncodedMapTest5
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:182;
+   * 
+   * @test_Strategy: Create multiple URI instances from the same UriBuilder
+   * instance using the UriBuilder.buildFromEncodedMap(Map); Verify that the
+   * builder is not affected.
+   */
+  @Test
+  public void buildFromEncodedMapTest5() throws Fault {
+    UriBuilder ub;
+
+    Map<String, String> maps = new HashMap<String, String>();
+    maps.put("x", "x%yz");
+    maps.put("y", "/path-absolute/test1");
+    maps.put("z", "fred@example.com");
+    maps.put("w", "path-rootless/test2");
+
+    Map<String, String> maps1 = new HashMap<String, String>();
+    maps1.put("x", "x%20yz");
+    maps1.put("y", "/path-absolute/test1");
+    maps1.put("z", "fred@example.com");
+    maps1.put("w", "path-rootless/test2");
+
+    Map<String, String> maps2 = new HashMap<String, String>();
+    maps2.put("x", "x%yz");
+    maps2.put("y", "/path-absolute/test1");
+    maps2.put("z", "fred@example.com");
+    maps2.put("w", "path-rootless/test2");
+    maps2.put("v", "xyz");
+
+    String expected_path_1 = "path-rootless/test2/x%20yz//path-absolute/test1/fred@example.com/x%20yz";
+
+    try {
+      ub = UriBuilder.fromPath("").path("{w}/{x}/{y}/{z}/{x}");
+
+      uri = ub.buildFromEncodedMap(maps);
+      gotExpectedPass(uri.getRawPath(), EXPECTED_PATH);
+
+      uri = ub.buildFromEncodedMap(maps1);
+      gotExpectedPass(uri.getRawPath(), expected_path_1);
+
+      uri = ub.buildFromEncodedMap(maps2);
+      gotExpectedPass(uri.getRawPath(), EXPECTED_PATH);
+    } catch (Throwable ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage() + newline);
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: fromPathTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:176; JAXRS:JAVADOC:190;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath(String)
+   */
+  @Test
+  public void fromPathTest1() throws Fault {
+    String[] paths = { "/", "", "/path-absolute/test1", "fred@example.com",
+        "path-rootless/test2" };
+
+    int j = 0;
+    while (j < paths.length) {
+      try {
+        uri = UriBuilder.fromPath(paths[j]).build();
+        gotExpectedPass(uri.getPath(), paths[j]);
+      } catch (Exception ex) {
+        pass = false;
+        sb.append("Unexpected exception thrown: " + ex.getMessage());
+      }
+      j++;
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: fromPathTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:191;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath(null) Verify that IllegalArgumentException is thrown.
+   */
+  @Test
+  public void fromPathTest2() throws Fault {
+    String path = null;
+
+    try {
+      UriBuilder.fromPath(path);
+      throw new Fault(
+          "Test Failed: expected IllegalArgumentException not thrown");
+    } catch (IllegalArgumentException ilex) {
+    }
+  }
+
+  /*
+   * @testName: fromResourceTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:192;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromResource(null) Verify that IllegalArgumentException is
+   * thrown.
+   */
+  @Test
+  public void fromResourceTest1() throws Fault {
+    Class<?> res = null;
+
+    try {
+      UriBuilder.fromResource(res);
+      throw new Fault(
+          "Test Failed: expected IllegalArgumentException not thrown");
+    } catch (IllegalArgumentException ilex) {
+    }
+  }
+
+  /*
+   * @testName: fromResourceTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:192;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromResource(Class) Verify that Uri can be built from it with
+   * correct path.
+   */
+  @Test
+  public void fromResourceTest2() throws Fault {
+    Class<?> res = jakarta.ws.rs.tck.api.rs.core.uribuilder.TestPath.class;
+    String expected_path = "/TestPath";
+
+    try {
+      uri = UriBuilder.fromResource(res).build();
+      gotExpectedPass(uri.toString(), expected_path);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: fromUriTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:194;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromUri((URI)null) Verify that IllegalArgumentException is
+   * thrown.
+   */
+  @Test
+  public void fromUriTest1() throws Fault {
+    try {
+      UriBuilder.fromUri(uri);
+
+      throw new Fault(
+          "Test Failed: expected IllegalArgumentException not thrown");
+    } catch (IllegalArgumentException ilex) {
+    }
+  }
+
+  /*
+   * @testName: fromUriTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:196;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromUri((String)null) Verify that IllegalArgumentException is
+   * thrown.
+   */
+  @Test
+  public void fromUriTest2() throws Fault {
+    String uri = null;
+
+    try {
+      UriBuilder.fromUri(uri);
+      throw new Fault(
+          "Test Failed: expected IllegalArgumentException not thrown");
+    } catch (IllegalArgumentException ilex) {
+    }
+  }
+
+  /*
+   * @testName: fromUriTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:176; JAXRS:JAVADOC:196;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromUri(String)
+   */
+  @Test
+  public void fromUriTest3() throws Fault {
+    String[] uris = { "ftp://ftp.is.co.za/rfc/rfc1808.txt",
+        "mailto:java-net@java.sun.com", "news:comp.lang.java",
+        "urn:isbn:096139210x", "http://www.ietf.org/rfc/rfc2396.txt",
+        "ldap://[2001:db8::7]/c=GB?objectClass?one", "tel:+1-816-555-1212",
+        "telnet://192.0.2.16:80/",
+        "foo://example.com:8042/over/there?name=ferret#nose" };
+
+    int j = 0;
+    while (j < 9) {
+      try {
+        uri = UriBuilder.fromUri(uris[j]).build();
+        gotExpectedPass(uri.toString().trim(), uris[j]);
+      } catch (Exception ex) {
+        pass = false;
+        sb.append("Unexpected exception thrown: " + ex.getMessage());
+      }
+      j++;
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: fromUriTest4
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:176; JAXRS:JAVADOC:194;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using UriBuilder.fromUri(URI)
+   */
+  @Test
+  public void fromUriTest4() throws Fault {
+    String[] uris = { "ftp://ftp.is.co.za/rfc/rfc1808.txt",
+        "mailto:java-net@java.sun.com", "news:comp.lang.java",
+        "urn:isbn:096139210x", "http://www.ietf.org/rfc/rfc2396.txt",
+        "ldap://[2001:db8::7]/c=GB?objectClass?one", "tel:+1-816-555-1212",
+        "telnet://192.0.2.16:80/",
+        "foo://example.com:8042/over/there?name=ferret#nose" };
+
+    int j = 0;
+    while (j < 9) {
+      try {
+        uri = UriBuilder.fromUri(new URI(uris[j])).build();
+        gotExpectedPass(uri.toString().trim(), uris[j]);
+      } catch (Exception ex) {
+        pass = false;
+        sb.append("Unexpected exception thrown: " + ex.getMessage());
+      }
+      j++;
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: pathTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:202;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath(String).path("/TestPath"), Verify that "/TestPath" is
+   * appended as specified
+   */
+  @Test
+  public void pathTest() throws Fault {
+    String path = "test1#test2";
+    String path1 = "/TestPath";
+    String expected_path = "test1%23test2/TestPath";
+
+    try {
+      URI uri = UriBuilder.fromPath(path).path(path1).build();
+      gotExpectedPass(uri.toString(), expected_path);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: pathTest0
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:202;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath(String).path("TestPath"), Verify that "TestPath" is
+   * appended as specified
+   */
+  @Test
+  public void pathTest0() throws Fault {
+    String path = "test1#test2";
+    String path1 = "TestPath";
+    String expected_path = "test1%23test2/TestPath";
+
+    try {
+      URI uri = UriBuilder.fromPath(path).path(path1).build();
+      gotExpectedPass(uri.toString(), expected_path);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: pathTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:202;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath(String).path(String null), Verify that
+   * IllegalArgumentException is thrown
+   */
+  @Test
+  public void pathTest1() throws Fault {
+    String path = "test1#test2";
+    String path1 = null;
+
+    try {
+      UriBuilder.fromPath(path).path(path1);
+      throw new Fault(
+          "Test Failed.  Expected IllegalArgumentException not thrown.");
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace(
+          "Expected IllegalArgumentException thrown: " + ilex.getMessage());
+    }
+  }
+
+  /*
+   * @testName: pathTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:204;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath(String).path(Class TestPath), TestPath is annonated
+   * with @Path, Verify that TestPath is appended as specified
+   */
+  @Test
+  public void pathTest2() throws Fault {
+    String path = "test1#test2";
+    Class<?> path1 = jakarta.ws.rs.tck.api.rs.core.uribuilder.TestPath.class;
+    String expected_path = "test1%23test2/TestPath";
+
+    try {
+      uri = UriBuilder.fromPath(path).path(path1).build();
+      gotExpectedPass(uri.toString(), expected_path);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: pathTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:204;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath(String).path(Class null), Verify that
+   * IllegalArgumentException is thrown
+   */
+  @Test
+  public void pathTest3() throws Fault {
+    String path = "test1#test2";
+    Class<?> path1 = null;
+
+    try {
+      UriBuilder.fromPath(path).path(path1);
+      throw new Fault(
+          "Test Failed.  Expected IllegalArgumentException not thrown.");
+
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace(
+          "Expected IllegalArgumentException thrown: " + ilex.getMessage());
+    }
+  }
+
+  /*
+   * @testName: pathTest4
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:204;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath(String).path(Class TestPathBad), TestPathBad is not
+   * annonated with @Path, Verify that IllegalArgumentException is thrown
+   */
+  @Test
+  public void pathTest4() throws Fault {
+    String path = "test1#test2";
+    Class<?> path1 = jakarta.ws.rs.tck.api.rs.core.uribuilder.TestPathBad.class;
+
+    try {
+      UriBuilder.fromPath(path).path(path1);
+      throw new Fault(
+          "Test Failed.  Expected IllegalArgumentException not thrown.");
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace(
+          "Expected IllegalArgumentException thrown: " + ilex.getMessage());
+    }
+  }
+
+  /*
+   * @testName: pathTest5
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:206;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath("/TestPath").path(Class TestPath, String "headSub"),
+   * Verify that "/sub" is appended as specified
+   */
+  @Test
+  public void pathTest5() throws Fault {
+    String path = "/TestPath";
+    Class<?> path1 = jakarta.ws.rs.tck.api.rs.core.uribuilder.TestPath.class;
+    String md = "headSub";
+    String expected_path = "/TestPath/sub";
+
+    try {
+      uri = UriBuilder.fromPath(path).path(path1, md).build();
+      gotExpectedPass(uri.toString(), expected_path);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: pathTest6
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:206;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath("/TestPath").path(Class TestPath, String "getPlain"),
+   * Verify that IllegalArgumentException is thrown since Method getPlain is not
+   * annonated with @Path
+   */
+  @Test
+  public void pathTest6() throws Fault {
+    String path = "/TestPath";
+    Class<?> path1 = jakarta.ws.rs.tck.api.rs.core.uribuilder.TestPath.class;
+    String md = "getPlain";
+
+    try {
+      UriBuilder.fromPath(path).path(path1, md).build();
+      throw new Fault(
+          "Test failed, expected IllegalArgumentException not thrown."
+              + newline);
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace(
+          "Expected IllegalArgumentException thrown: " + ilex.getMessage());
+    }
+  }
+
+  /*
+   * @testName: pathTest7
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:206;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath("/TestPath").path(Class TestPath, null), Verify that
+   * IllegalArgumentException is thrown
+   */
+  @Test
+  public void pathTest7() throws Fault {
+    String path = "/TestPath";
+    Class<?> path1 = jakarta.ws.rs.tck.api.rs.core.uribuilder.TestPath.class;
+    String md = null;
+
+    try {
+      UriBuilder.fromPath(path).path(path1, md).build();
+      throw new Fault(
+          "Test failed, expected IllegalArgumentException not thrown."
+              + newline);
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace(
+          "Expected IllegalArgumentException thrown: " + ilex.getMessage());
+    }
+  }
+
+  /*
+   * @testName: pathTest8
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:206;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath("/TestPath").path(Class null, "headSub"), Verify that
+   * IllegalArgumentException is thrown since Method getPlan is not annonated
+   * with @Path
+   */
+  @Test
+  public void pathTest8() throws Fault {
+    String path = "/TestPath";
+    Class<?> path1 = null;
+    String md = "headSub";
+
+    try {
+      UriBuilder.fromPath(path).path(path1, md).build();
+      throw new Fault(
+          "Test failed, expected IllegalArgumentException not thrown."
+              + newline);
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace(
+          "Expected IllegalArgumentException thrown: " + ilex.getMessage());
+    }
+  }
+
+  /*
+   * @testName: pathTest9
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:206;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath(String).path(TestPath,"test1"), Verify that
+   * IllegalArgumentException is thrown, since there are two methods annotated
+   * with @Path in TestPath
+   */
+  @Test
+  public void pathTest9() throws Fault {
+    String path = "/TestPath";
+    Class<?> path1 = jakarta.ws.rs.tck.api.rs.core.uribuilder.TestPath.class;
+    String md = "test1";
+
+    try {
+      UriBuilder.fromPath(path).path(path1, md).build();
+      throw new Fault(
+          "Test Failed.  Expected IllegalArgumentException not thrown.");
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace(
+          "Expected IllegalArgumentException thrown: " + ilex.getMessage());
+    }
+  }
+
+  /*
+   * @testName: pathTest10
+   *
+   * @assertion_ids: JAXRS:JAVADOC:208;
+   *
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath("/TestPath").path(Method headSub), Verify that "/sub"
+   * is appended as specified
+   */
+  @Test
+  public void pathTest10() throws Fault {
+    String path = "/TestPath";
+    Class<?> path1 = jakarta.ws.rs.tck.api.rs.core.uribuilder.TestPath.class;
+    String expected_path = "/TestPath/sub";
+
+    try {
+      Method md = path1.getMethod("headSub", new Class[] {});
+      URI uri = UriBuilder.fromPath(path).path(md).build();
+      gotExpectedPass(uri.toString(), expected_path);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: pathTest11
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:208;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath("/TestPath").path(Method headSub), Verify that "/sub1"
+   * is appended as specified
+   */
+  @Test
+  public void pathTest11() throws Fault {
+    String path = "/TestPath";
+    Class<?> path1 = jakarta.ws.rs.tck.api.rs.core.uribuilder.TestPath.class;
+    String expected_path = "/TestPath/sub1";
+
+    try {
+      Method md = path1.getMethod("test1", new Class[] {});
+      URI uri = UriBuilder.fromPath(path).path(md).build();
+      gotExpectedPass(uri.toString(), expected_path);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: pathTest12
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:208;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath(String).path(Method getPlain), Verify that
+   * IllegalArgumentException is thrown
+   */
+  @Test
+  public void pathTest12() throws Fault {
+    String path = "/TestPath";
+    Class<?> path1 = jakarta.ws.rs.tck.api.rs.core.uribuilder.TestPath.class;
+
+    try {
+      Method md = path1.getMethod("getPlain", new Class[] {});
+      UriBuilder.fromPath(path).path(md).build();
+
+      throw new Fault(
+          "Test Failed.  Expected IllegalArgumentException not thrown.");
+
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace(
+          "Expected IllegalArgumentException thrown: " + ilex.getMessage());
+    } catch (NoSuchMethodException ex) {
+      throw new Fault(
+          "Test Failed.  Unexpected exception thrown: " + ex.getMessage());
+    }
+  }
+
+  /*
+   * @testName: pathTest13
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:208;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath(String).path(Method null), Verify that
+   * IllegalArgumentException is thrown
+   */
+  @Test
+  public void pathTest13() throws Fault {
+    String path = "test1#test2";
+    java.lang.reflect.Method path1 = null;
+
+    try {
+      UriBuilder.fromPath(path).path(path1);
+      throw new Fault(
+          "Test Failed.  Expected IllegalArgumentException not thrown.");
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace(
+          "Expected IllegalArgumentException thrown: " + ilex.getMessage());
+    }
+  }
+
+  /*
+   * @testName: replacePathTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:218;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath("/TestPath").replacePath(String newPath), Verify that
+   * path is updated as specified
+   */
+  @Test
+  public void replacePathTest1() throws Fault {
+    String path = "/TestPath";
+    String new_path = "/TestPathAgain";
+
+    try {
+      URI uri = UriBuilder.fromPath(path).replacePath(new_path).build();
+      gotExpectedPass(uri.toString(), new_path);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: replacePathTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:218;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath("/TestPath1/TestPath2").replacePath(String null),
+   * Verify that all existing path cleared as specified
+   */
+  @Test
+  public void replacePathTest2() throws Fault {
+    String path = "/TestPath1/TestPath2";
+    String new_path = null;
+
+    try {
+      URI uri = UriBuilder.fromPath(path).replacePath(new_path).build();
+      boolean conditionTrue = uri.toString() == null
+          || uri.toString().trim().compareTo("") == 0;
+      gotExpectedPass(!conditionTrue, uri.toString(), new_path);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: replacePathTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:218;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath("TestPath").replacePath(String newPath), Verify that
+   * all existing path cleared as specified
+   */
+  @Test
+  public void replacePathTest3() throws Fault {
+    String path = "TestPath";
+    String new_path = null;
+
+    try {
+      uri = UriBuilder.fromPath(path).replacePath(new_path).build();
+      boolean conditionTrue = uri.toString() == null
+          || uri.toString().trim().compareTo("") == 0;
+      gotExpectedPass(!conditionTrue, uri.toString(), new_path);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: portTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:210;
+   * 
+   * @test_Strategy: Call UriBuilder.port(int), Veify that port number updated
+   * accordingly.
+   */
+  @Test
+  public void portTest1() throws Fault {
+    String uri_string = "foo://example.com:8042/over/there?name=ferret#nose";
+    String uri_string_expected = "foo://example.com:2008/over/there?name=ferret#nose";
+    int port = 2008;
+
+    try {
+      uri = UriBuilder.fromUri(uri_string).port(port).build();
+      gotExpectedPass(uri.toString().trim(), uri_string_expected);
+    } catch (Exception ex) {
+      throw new Fault("Test Failed: unexpected Exception thrown", ex);
+    }
+  }
+
+  /*
+   * @testName: portTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:210;
+   * 
+   * @test_Strategy: Call UriBuilder.port(int) with an invalid port number;
+   * Verify that IllegalArgumentException is thrown.
+   */
+  @Test
+  public void portTest2() throws Fault {
+    String uri_string = "foo://example.com:8042/over/there?name=ferret#nose";
+    int port = -10;
+
+    try {
+      uri = UriBuilder.fromUri(uri_string).port(port).build();
+      throw new Fault(
+          "Test failed, expected IllegalArgumentException not thrown."
+              + "Got uri=" + uri.toString() + " instead.");
+    } catch (IllegalArgumentException ex) {
+      TestUtil
+          .logTrace("Test Passed: expected IllegalArgumentException thrown");
+    }
+  }
+
+  /*
+   * @testName: hostTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:198;
+   * 
+   * @test_Strategy: Call UriBuilder.host(String), verify that hostame updated
+   * accordingly
+   */
+  @Test
+  public void hostTest1() throws Fault {
+    String uri_string = "foo://example.com:8042/over/there?name=ferret#nose";
+    String uri_string_1 = "foo://java.net:8042/over/there?name=ferret#nose";
+    String host = "java.net";
+
+    try {
+      uri = UriBuilder.fromUri(uri_string).host(host).build();
+      gotExpectedPass(uri.toString().trim(), uri_string_1);
+    } catch (Exception ex) {
+      throw new Fault("Test Failed: unexpected Exception thrown", ex);
+    }
+  }
+
+  /*
+   * @testName: hostTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:198;
+   * 
+   * @test_Strategy: Call UriBuilder.host(hostname) with incorrect hstname,
+   * verify that IllegalArgumentException is thrown.
+   */
+  @Test
+  public void hostTest2() throws Fault {
+    String uri_string = "foo://example.com:8042/over/there?name=ferret#nose";
+    String host = "";
+
+    try {
+      uri = UriBuilder.fromUri(uri_string).host(host).build();
+      throw new Fault(
+          "Test failed, expected IllegalArgumentException not thrown."
+              + "Got uri=" + uri.toString() + " instead.");
+    } catch (IllegalArgumentException ex) {
+      TestUtil
+          .logTrace("Test Passed: expected IllegalArgumentException thrown");
+    }
+  }
+
+  /*
+   * @testName: schemeTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:196; JAXRS:JAVADOC:223;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromUri(String)
+   */
+  @Test
+  public void schemeTest1() throws Fault {
+    String uri_string = "foo://example.com:8042/over/there?name=ferret#nose";
+    String uri_string_1 = "http://example.com:8042/over/there?name=ferret#nose";
+    String scheme = "http";
+
+    try {
+      uri = UriBuilder.fromUri(uri_string).scheme(scheme).build();
+      gotExpectedPass(uri.toString().trim(), uri_string_1);
+    } catch (Exception ex) {
+      throw new Fault("Test Failed: unexpected Exception thrown", ex);
+    }
+  }
+
+  /*
+   * @testName: schemeTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:223;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromUri(null); Verify that scheme is cleared.
+   */
+  @Test
+  public void schemeTest2() throws Fault {
+    String uri_string = "http://example.com:8042/over/there?name=ferret#nose";
+    String scheme = null;
+
+    try {
+      uri = UriBuilder.fromUri(uri_string).scheme(scheme).build();
+      assertTrue(uri.getRawSchemeSpecificPart() == null,
+          "scheme not cleared as expected, got"+ uri.getSchemeSpecificPart());
+    } catch (Throwable ex) {
+      TestUtil.logTrace(
+          "Unexpected Exception thrown. Test Failed." + ex.getMessage());
+    }
+  }
+
+  /*
+   * @testName: schemeSpecificPartTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:225;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromUri(String); Call method schemeSpecificPart(String) Verify
+   * the method works.
+   */
+  @Test
+  public void schemeSpecificPartTest() throws Fault {
+    String uri_1 = "http://example.com:8042/uber/here?name=ferret#nose";
+    String uri_2 = "//example1.com:8041/over/there?name=monkey";
+    String uri_3 = "http://example1.com:8041/over/there?name=monkey#nose";
+
+    try {
+      uri = UriBuilder.fromUri(uri_1).schemeSpecificPart(uri_2).build();
+      gotExpectedPass(uri.toString().trim(), uri_3);
+    } catch (Exception ex) {
+      throw new Fault("Test Failed: unexpected Exception thrown", ex);
+    }
+  }
+
+  /*
+   * @testName: schemeSpecificPartTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:225;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromUri(String); Call method schemeSpecificPart(null) Verify
+   * that IllegalArgumentException is thrown.
+   */
+  @Test
+  public void schemeSpecificPartTest1() throws Fault {
+    String uri_1 = "http://example.com:8042/uber/here?name=ferret#nose";
+    String uri_2 = null;
+
+    try {
+      UriBuilder.fromUri(uri_1).schemeSpecificPart(uri_2).build();
+      sb.append(
+          "Test Failed: expected IllegalArgumentException Exception not thrown.");
+      pass = false;
+    } catch (IllegalArgumentException ex) {
+      sb.append("Expected IllegalArgumentException thrown. Test PASSED.");
+    } catch (Exception ex) {
+      sb.append("Test Failed: wrong Exception thrown" + ex.getMessage());
+      pass = false;
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: templateTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:176; JAXRS:JAVADOC:189; JAXRS:JAVADOC:190;
+   * 
+   * @test_Strategy: Create an Uri instance using
+   * UriBuilder.fromPath(String).fragment(String).build(String)
+   */
+  @Test
+  public void templateTest1() throws Fault {
+    String expected_value = "test#xyz";
+
+    try {
+      uri = UriBuilder.fromPath("{arg1}").fragment("{arg2}").build("test",
+          "xyz");
+      gotExpectedPass(uri.toString(), expected_value);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: templateTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:176; JAXRS:JAVADOC:190;
+   * 
+   * @test_Strategy: Create an Uri instance using
+   * UriBuilder.fromPath(String).build(String)
+   */
+  @Test
+  public void templateTest2() throws Fault {
+    String expected_value = "test1/test2/test1";
+
+    try {
+      uri = UriBuilder.fromPath("{arg1}/{arg2}/{arg1}").build("test1", "test2",
+          "test3");
+      gotExpectedPass(uri.toString(), expected_value);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: uriTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:176; JAXRS:JAVADOC:194; JAXRS:JAVADOC:229;
+   * 
+   * @test_Strategy: Create a set of UriBuilder instances with diffeent schemes;
+   * using UriBuilder instances using UriBuilder.fromUri(URI) Call uri(URI)
+   * method on all instances; verify it works correctly on all of the instances.
+   */
+  @Test
+  public void uriTest() throws Fault {
+    String[] uris_orig = getOrigUris();
+    URI uris_replace[] = getReplacementUris();
+    String[] uris_expect = getExpectedUris();
+
+    int j = 0;
+    int i = 0;
+    int k = 0;
+    while (j < 17) {
+      try {
+        sb.append("Replace uri with ").append(uris_replace[j]).append(newline);
+        uri = UriBuilder.fromUri(new URI(uris_orig[j])).uri(uris_replace[j])
+            .build();
+        if (gotExpectedPass(uri.toString().trim(), uris_expect[j]) != 0)
+          i++;
+        else
+          k++;
+      } catch (Exception ex) {
+        pass = false;
+        sb.append("Unexpected exception thrown: ").append(ex.getMessage())
+            .append(newline);
+        sb.append("Test failed with exception for expected uri: ")
+            .append(uris_expect[j]).append(newline);
+      }
+      j++;
+    }
+
+    assertTrue(pass, k+ "assertion passed."+ newline+ i+ "assertion(s) failed:"+
+        sb.toString()+ newline);
+    logMsg(sb);
+  }
+
+  /*
+   * @testName: uriTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:229;
+   * 
+   * @test_Strategy: Calling UriBuilder.uri(URI null) verify the
+   * IllegalStateException thrown..
+   */
+  @Test
+  public void uriTest1() throws Fault {
+    try {
+      UriBuilder.fromPath("/").uri(uri);
+      throw new Fault("Expected IllegalArgumentException not thrown" + newline);
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace("Expected IllegalArgumentException thrown");
+    }
+  }
+
+  /*
+   * @testName: fromEncodedTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:179;
+   * 
+   * @test_Strategy: Calling UriBuilder.buildFromEncoded(Object...). verify
+   * Object.toString() is encoded.
+   */
+  @Test
+  public void fromEncodedTest1() throws Fault {
+    String expected_value_1 = "http://localhost:8080/a/%25/=/%25G0/%25/=";
+    String expected_value_2 = "http://localhost:8080/xy/%20/%25/xy";
+
+    try {
+      uri = UriBuilder.fromPath(LOCALHOST).path("/{v}/{w}/{x}/{y}/{z}/{x}")
+          .buildFromEncoded("a", "%25", "=", "%G0", "%", "23");
+      gotExpectedPass(uri.toString(), expected_value_1);
+
+      uri = UriBuilder.fromPath(LOCALHOST).path("/{x}/{y}/{z}/{x}")
+          .buildFromEncoded("xy", " ", "%");
+      gotExpectedPass(uri.toString(), expected_value_2);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: fromEncodedTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:180;
+   * 
+   * @test_Strategy: Calling UriBuilder.buildFromEncoded(Object...). verify
+   * IllegalArgumentException is thrown when one template is missing its value
+   */
+  @Test
+  public void fromEncodedTest2() throws Fault {
+    try {
+      uri = UriBuilder.fromPath(LOCALHOST).path("/{v}/{w}/{x}/{y}/{z}/{x}")
+          .buildFromEncoded("a", "%25", "=", "%G0");
+      throw new Fault("Expected IllegalArgumentException Not thrown. uri ="
+          + uri.toString());
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace("Expected IllegalArgumentException thrown");
+    }
+  }
+
+  /*
+   * @testName: fromEncodedTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:180;
+   * 
+   * @test_Strategy: Calling UriBuilder.buildFromEncoded(Object...). verify
+   * IllegalArgumentException is thrown when one value is null.
+   */
+  @Test
+  public void fromEncodedTest3() throws Fault {
+    try {
+      UriBuilder.fromPath(LOCALHOST).path("/{v}/{w}/{x}/{y}/{z}/{x}")
+          .buildFromEncoded("a", "%25", null, "%G0");
+      throw new Fault("Expected IllegalArgumentException Not thrown");
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace("Expected IllegalArgumentException thrown");
+    }
+  }
+
+  /*
+   * @testName: queryParamTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:212;
+   * 
+   * @test_Strategy: Calling UriBuilder.queryParam(String name, Object...
+   * value). verify IllegalArgumentException is thrown when name is null.
+   */
+  @Test
+  public void queryParamTest1() throws Fault {
+    String name = null;
+
+    try {
+      UriBuilder.fromPath(LOCALHOST).queryParam(name, "x", "y");
+      throw new Fault("Expected IllegalArgumentException Not thrown");
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace("Expected IllegalArgumentException thrown");
+    }
+  }
+
+  /*
+   * @testName: queryParamTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:212;
+   * 
+   * @test_Strategy: Calling UriBuilder.queryParam(String name, Object...
+   * value). verify IllegalArgumentException is thrown when values is null.
+   */
+  @Test
+  public void queryParamTest2() throws Fault {
+    String name = "name";
+
+    try {
+      UriBuilder.fromPath(LOCALHOST).queryParam(name, (Object) null);
+      throw new Fault("Expected IllegalArgumentException Not thrown");
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace("Expected IllegalArgumentException thrown");
+    }
+  }
+
+  /*
+   * @testName: queryParamTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:212;
+   * 
+   * @test_Strategy: Calling UriBuilder.queryParam(String name, Object...
+   * value). verify IllegalArgumentException is thrown when one of values is
+   * null.
+   */
+  @Test
+  public void queryParamTest3() throws Fault {
+    String name = "name";
+
+    try {
+      UriBuilder.fromPath(LOCALHOST).queryParam(name, "x", null);
+      throw new Fault("Expected IllegalArgumentException Not thrown");
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace("Expected IllegalArgumentException thrown");
+    }
+  }
+
+  /*
+   * @testName: queryParamTest4
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:212;
+   * 
+   * @test_Strategy: Calling UriBuilder.queryParam(String name, Object...
+   * value). verify that when two values are supplied, both are present in final
+   * URI.
+   */
+  @Test
+  public void queryParamTest4() throws Fault {
+    String name = "name";
+    String expected_value = "http://localhost:8080?name=x&name=y";
+
+    try {
+      uri = UriBuilder.fromPath(LOCALHOST).queryParam(name, "x", "y").build();
+      gotExpectedPass(uri.toString(), expected_value);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: queryParamTest5
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:212;
+   * 
+   * @test_Strategy: Calling UriBuilder.queryParam(String name, Object...
+   * value). verify that values are encoded properly in final URI.
+   */
+  @Test
+  public void queryParamTest5() throws Fault {
+    String name = "name";
+    String actual = null;
+    String expected_value = "http://localhost:8080?name=x%3D&name=y?&name=x+y&name=%26";
+
+    try {
+      uri = UriBuilder.fromPath(LOCALHOST)
+          .queryParam(name, "x=", "y?", "x y", "&").build();
+      actual = uri.toString().replace("%3F", "?").replace("%3f", "?");
+      gotExpectedPass(actual, expected_value);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: replaceQueryTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:219;
+   * 
+   * @test_Strategy: Calling UriBuilder.replaceQuery(String name). verify that
+   * query is replaced properly in final URI.
+   */
+  @Test
+  public void replaceQueryTest1() throws Fault {
+    String name = "name";
+    String expected_value = "http://localhost:8080?name1=xyz";
+
+    try {
+      uri = UriBuilder.fromPath(LOCALHOST)
+          .queryParam(name, "x=", "y?", "x y", "&").replaceQuery("name1=xyz")
+          .build();
+      gotExpectedPass(uri.toString(), expected_value);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: replaceQueryTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:219;
+   * 
+   * @test_Strategy: Calling UriBuilder.replaceQuery(String null). verify that
+   * query is cleared properly in final URI.
+   */
+  @Test
+  public void replaceQueryTest2() throws Fault {
+    String name = "name";
+
+    try {
+      uri = UriBuilder.fromPath(LOCALHOST)
+          .queryParam(name, "x=", "y?", "x y", "&").replaceQuery(null).build();
+      gotExpectedPass(uri.toString(), LOCALHOST);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: replaceQueryTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:219;
+   * 
+   * @test_Strategy: Calling UriBuilder.replaceQuery(String query). verify that
+   * query is replaced properly in final URI.
+   */
+  @Test
+  public void replaceQueryTest3() throws Fault {
+    String name = "name";
+    String expected_value = "http://localhost:8080?name1=x&name2=%20&name3=x+y&name4=23&name5=x%20y";
+
+    try {
+      uri = UriBuilder.fromPath(LOCALHOST)
+          .queryParam(name, "x=", "y?", "x y", "&")
+          .replaceQuery("name1=x&name2=%20&name3=x+y&name4=23&name5=x y")
+          .build();
+      gotExpectedPass(uri.toString(), expected_value);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * testName: replaceQueryTest4
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:219;
+   * 
+   * @test_Strategy: Calling UriBuilder.replaceQuery(String query). verify that
+   * IllegalArgumentException is thrown when query cannot be parsed.
+   */
+  @Test
+  public void replaceQueryTest4() throws Fault {
+    String value = "http://localhost:8080?name1=x&name2=%20&name3=x+y&name4=x%20y";
+
+    try {
+      uri = UriBuilder.fromPath(value)
+          .replaceQuery("name$*()^@!+-]}[{|<>,./:;'#1==x?&name2=%20y").build();
+      pass = false;
+      sb.append("Expected IllegalArgumentException not thrown");
+      sb.append("uri=" + uri.getQuery());
+    } catch (IllegalArgumentException ex) {
+      sb.append("Expected IllegalArgumentException thrown");
+    } catch (Exception ex1) {
+      pass = false;
+      sb.append("Wrong type Exception thrown" + ex1.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: replaceQueryParamTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:221;
+   * 
+   * @test_Strategy: Calling UriBuilder.replaceQueryParam(String null, Object...
+   * value). verify IllegalArgumentException is thrown
+   */
+  @Test
+  public void replaceQueryParamTest1() throws Fault {
+    String name = null;
+
+    try {
+      UriBuilder.fromPath(LOCALHOST).queryParam(name, "x", null);
+      throw new Fault("Expected IllegalArgumentException Not thrown");
+    } catch (IllegalArgumentException ilex) {
+      TestUtil.logTrace("Expected IllegalArgumentException thrown");
+    }
+  }
+
+  /*
+   * @testName: replaceQueryParamTest2
+   *
+   * @assertion_ids: JAXRS:JAVADOC:221;
+   *
+   * @test_Strategy: Calling UriBuilder.replaceQueryParam(String name, Object...
+   * value). verify all query params are cleared when values is null.
+   */
+  @Test
+  public void replaceQueryParamTest2() throws Fault {
+    String name = "name";
+
+    try {
+      uri = UriBuilder.fromPath(LOCALHOST)
+          .queryParam(name, "x=", "y?", "x y", "&")
+          .replaceQueryParam(name, (Object[]) null).build();
+      gotExpectedPass(uri.toString(), LOCALHOST);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: replaceQueryParamTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:221;
+   * 
+   * @test_Strategy: Calling UriBuilder.replaceQueryParam(String name, Object...
+   * value). verify that query parameter is updated accordingly
+   */
+  @Test
+  public void replaceQueryParamTest3() throws Fault {
+    String name = "name";
+    String expected_value = "http://localhost:8080?name=x&name=y&name=y+x&name=x%25y&name=%20";
+    try {
+      uri = UriBuilder.fromPath(LOCALHOST)
+          .queryParam(name, "x=", "y?", "x y", "&")
+          .replaceQueryParam(name, "x", "y", "y x", "x%y", "%20").build();
+      gotExpectedPass(uri.toString(), expected_value);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: segmentTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:227;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath("/TestPath").segment(String[] paths), Verify
+   * IllegalArgumentException if any element of paths is null
+   */
+  @Test
+  public void segmentTest1() throws Fault {
+    String path = null;
+
+    try {
+      UriBuilder.fromPath("/").segment(path).build();
+      throw new Fault(
+          "TestFailed: expected IllegalArgumentException not thrown.");
+
+    } catch (IllegalArgumentException ex) {
+      TestUtil
+          .logTrace("Test Passed: Expected IllegalArgumentException thrown.");
+    }
+  }
+
+  /*
+   * @testName: segmentTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:227;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath("/TestPath").segment(String[] paths), Verify "/" is
+   * added when needed and characters are encoded as needed.
+   */
+  @Test
+  public void segmentTest2() throws Fault {
+    String path1 = "";
+    String[] path2 = { "a1", "/", "3b " };
+    String expected_path = "a1/%2F/3b%20";
+
+    try {
+      uri = UriBuilder.fromPath(path1).segment(path2).build();
+      gotExpectedPass(uri.toString(), expected_path);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: segmentTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:227;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath("/TestPath").segment(String[] paths), Verify that a
+   * single value is only a single URI path segment. and characters are encoded
+   * as needed.
+   */
+  @Test
+  public void segmentTest3() throws Fault {
+    String path1 = "ab";
+    String[] path2 = { "a1", "x/y", "3b " };
+    String expected_path = "ab/a1/x%2Fy/3b%20";
+
+    try {
+      uri = UriBuilder.fromPath(path1).segment(path2).build();
+      gotExpectedPass(uri.toString(), expected_path);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: uriBuilderExceptionTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:232;
+   * 
+   * @test_Strategy: Create an UriBuilderException instance using
+   * UriBuilderException(). Verify that empty message is associated with the
+   * exception.
+   */
+  @Test
+  public void uriBuilderExceptionTest1() throws Fault {
+    try {
+      throw new UriBuilderException();
+    } catch (UriBuilderException ube) {
+      if (ube.getMessage() == "" || ube.getMessage() == null) {
+        TestUtil.logTrace(
+            "Test Passed with empty message: " + ube.getMessage() + ".");
+      } else {
+        throw new Fault("Test Failed.  Expecting empty message," + " Got "
+            + ube.getMessage());
+      }
+    }
+  }
+
+  /*
+   * @testName: uriBuilderExceptionTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:233;
+   * 
+   * @test_Strategy: Create an UriBuilderException instance using
+   * UriBuilderException(String msg). Verify that message msg is associated with
+   * the exception.
+   */
+  @Test
+  public void uriBuilderExceptionTest2() throws Fault {
+    String msg = "JAX-RS Test Message: xyz";
+
+    try {
+      throw new UriBuilderException(msg);
+    } catch (UriBuilderException ube) {
+      if (msg.equals(ube.getMessage())) {
+        TestUtil.logTrace(
+            "Test Passed with correct message: " + ube.getMessage() + ".");
+      } else {
+        throw new Fault("Test Failed.  Expecting message," + msg + ", got "
+            + ube.getMessage() + ".");
+      }
+    }
+  }
+
+  /*
+   * @testName: uriBuilderExceptionTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:234;
+   * 
+   * @test_Strategy: Create an UriBuilderException instance using
+   * UriBuilderException(String msg, throwable ex). Verify that message msg is
+   * associated with the exception.
+   */
+  @Test
+  public void uriBuilderExceptionTest3() throws Fault {
+    String msg = "JAX-RS Test Message: xyz";
+    String msg1 = "JAX-RS Test Message Again: xyz";
+
+    try {
+      throw new UriBuilderException(msg, new Exception(msg1));
+    } catch (UriBuilderException ube) {
+      if (ube.getMessage().contains(msg)) {
+        TestUtil.logTrace(
+            "Test Passed with correct message: " + ube.getMessage() + ".");
+      } else {
+        throw new Fault("Test Failed.  Expecting message," + msg + ", got "
+            + ube.getMessage() + ".");
+      }
+    }
+  }
+
+  /*
+   * @testName: uriBuilderExceptionTest4
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:235;
+   * 
+   * @test_Strategy: Create an UriBuilderException instance using
+   * UriBuilderException(String msg, throwable ex). Verify that message msg is
+   * associated with the exception.
+   */
+  @Test
+  public void uriBuilderExceptionTest4() throws Fault {
+    String msg = "JAX-RS Test Message Again: xyz";
+
+    try {
+      throw new UriBuilderException(new Exception(msg));
+    } catch (UriBuilderException ube) {
+      if (ube.getMessage().contains(msg)) {
+        TestUtil.logTrace(
+            "Test Passed with correct message: " + ube.getMessage() + ".");
+      } else {
+        throw new Fault("Test Failed.  Expecting message," + msg + ", got "
+            + ube.getMessage() + ".");
+      }
+    }
+  }
+
+  /*
+   * @testName: cloneTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:188;
+   * 
+   * @test_Strategy: Create an UriBuilder instance using
+   * UriBuilder.fromPath(String); Create another UriBuilder instance using
+   * UriBuilder.clone(); Verify that both are created correctly.
+   */
+  @Test
+  public void cloneTest1() throws Fault {
+    UriBuilder ub, ub1;
+    URI uri1;
+    String path1 = "test";
+    String frag = "xyz";
+    String expected_path_1 = "test#xyz";
+
+    Map<String, String> maps = new HashMap<String, String>();
+    maps.put("x", "x%yz");
+    maps.put("y", "/path-absolute/%25test1");
+    maps.put("z", "fred@example.com");
+    maps.put("w", "path-rootless/test2");
+
+    String expected_path_2 = "test/" + ENCODED_EXPECTED_PATH + "#xyz";
+
+    try {
+      ub = UriBuilder.fromPath(path1).fragment(frag);
+      ub1 = ub.clone();
+      uri = ub.build();
+      gotExpectedPass(uri.toString(), expected_path_1);
+
+      uri1 = ub1.path("{w}/{x}/{y}/{z}/{x}").buildFromMap(maps);
+      gotExpectedPass(uri1.toString(), expected_path_2);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected exception thrown: " + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: matrixParamTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:200;
+   * 
+   * @test_Strategy: Calling UriBuilder.matrixParam(String name, Object...
+   * value). verify IllegalArgumentException is thrown when name is null.
+   */
+  @Test
+  public void matrixParamTest1() throws Fault {
+    String name = null;
+
+    try {
+      UriBuilder.fromPath(LOCALHOST).matrixParam(name, "x", "y");
+      sb.append("Expected IllegalArgumentException Not thrown");
+      pass = false;
+    } catch (IllegalArgumentException ilex) {
+      sb.append("Expected IllegalArgumentException thrown");
+    } catch (Throwable th) {
+      pass = false;
+      sb.append("Incorrect Exception thrown: " + th.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: matrixParamTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:200;
+   * 
+   * @test_Strategy: Calling UriBuilder.matrixParam(String name, Object...
+   * value). verify IllegalArgumentException is thrown when values is null.
+   */
+  @Test
+  public void matrixParamTest2() throws Fault {
+    String name = "name";
+
+    try {
+      UriBuilder.fromPath(LOCALHOST).matrixParam(name, (Object) null);
+      sb.append("Expected IllegalArgumentException Not thrown");
+      pass = false;
+    } catch (IllegalArgumentException ilex) {
+      sb.append("Expected IllegalArgumentException thrown");
+    } catch (Throwable th) {
+      pass = false;
+      sb.append("Incorrect Exception thrown: " + th.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: matrixParamTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:200;
+   * 
+   * @test_Strategy: Calling UriBuilder.matrixParam(String name, Object...
+   * value). verify that when two values are supplied, both are present in final
+   * URI.
+   */
+  @Test
+  public void matrixParamTest3() throws Fault {
+    String name = "name";
+    String expected_value = "http://localhost:8080;name=x;name=y";
+
+    try {
+      uri = UriBuilder.fromPath(LOCALHOST).matrixParam(name, "x", "y").build();
+      gotExpectedPass(uri.toString(), expected_value);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: replaceMatrixParamTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:216;
+   * 
+   * @test_Strategy: Calling UriBuilder.replaceMatrixParam(String name,
+   * Object... value). verify IllegalArgumentException when name is null.
+   */
+  @Test
+  public void replaceMatrixParamTest1() throws Fault {
+    String name = "name";
+
+    try {
+      UriBuilder.fromPath(LOCALHOST).matrixParam(name, "x=", "y?", "x y", "&")
+          .replaceMatrixParam(null, "x", "y").build();
+      pass = false;
+      sb.append("Expected exception not thrown.");
+    } catch (IllegalArgumentException ex) {
+      sb.append("Expected exception thrown.");
+    } catch (Throwable th) {
+      pass = false;
+      sb.append("Wrong type of  Exception thrown" + th.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: replaceMatrixParamTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:216;
+   * 
+   * @test_Strategy: Calling UriBuilder.replaceMatrixParam(String name,
+   * Object... value). verify all values are cleared when value is null.
+   */
+  @Test
+  public void replaceMatrixParamTest2() throws Fault {
+    String name = "name";
+
+    try {
+      uri = UriBuilder.fromPath(LOCALHOST)
+          .matrixParam(name, "x=", "y?", "x y", "&").replaceMatrixParam(name)
+          .build();
+      gotExpectedPass(uri.toString(), LOCALHOST);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: replaceMatrixParamTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:216;
+   * 
+   * @test_Strategy: Calling UriBuilder.replaceMatrixParam(String name,
+   * Object... value). verify that matrix parameter is updated accordingly
+   */
+  @Test
+  public void replaceMatrixParamTest3() throws Fault {
+    String name = "name";
+    String expected = "http://localhost:8080;name=x;name=y;name=y%20x;name=x%25y;name=%20";
+
+    try {
+      uri = UriBuilder
+          .fromPath("http://localhost:8080;name=x=;name=y?;name=x y;name=&")
+          .replaceMatrixParam(name, "x", "y", "y x", "x%y", "%20").build();
+      gotExpectedPass(uri.toString(), expected);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: replaceMatrixParamTest4
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:216;
+   * 
+   * @test_Strategy: Calling UriBuilder.replaceMatrixParam(String name,
+   * Object... value). verify that matrix parameter is updated accordingly
+   */
+  @Test
+  public void replaceMatrixParamTest4() throws Fault {
+    String name = "name1";
+    String expected = "http://localhost:8080;name=x=;name=y%3F;name=x%20y;name=&;name1=x;name1=y;name1=y%20x;name1=x%25y;name1=%20";
+
+    try {
+      uri = UriBuilder
+          .fromPath("http://localhost:8080;name=x=;name=y?;name=x y;name=&")
+          .replaceMatrixParam(name, "x", "y", "y x", "x%y", "%20").build();
+      gotExpectedPass(uri.toString(), expected);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: replaceMatrixTest1
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:214;
+   * 
+   * @test_Strategy: Calling UriBuilder.replaceMatrix(String value). verify all
+   * values are cleared when value is null.
+   */
+  @Test
+  public void replaceMatrixTest1() throws Fault {
+    String name = "name";
+    String expected1 = "http://localhost:8080;";
+
+    try {
+      uri = UriBuilder.fromPath(LOCALHOST)
+          .matrixParam(name, "x=", "y?", "x y", "&").replaceMatrix(null)
+          .build();
+      String sUri = uri.toString();
+      boolean condition = sUri.compareToIgnoreCase(LOCALHOST) == 0
+          || sUri.compareToIgnoreCase(expected1) == 0;
+      gotExpectedPass(!condition, sUri, LOCALHOST);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: replaceMatrixTest2
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:214;
+   * 
+   * @test_Strategy: Calling UriBuilder.replaceMatrix(String value). verify that
+   * Matrix parameter is updated accordingly
+   */
+  @Test
+  public void replaceMatrixTest2() throws Fault {
+    String expected = "http://localhost:8080;name=x;name=y;name=y%20x;name=x%25y;name=%20";
+    String value = "name=x;name=y;name=y x;name=x%y;name= ";
+
+    try {
+      uri = UriBuilder
+          .fromPath("http://localhost:8080;name=x=;name=y?;name=x y;name=&")
+          .replaceMatrix(value).build();
+      gotExpectedPass(uri.toString(), expected);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: replaceMatrixTest3
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:214;
+   * 
+   * @test_Strategy: Calling UriBuilder.replaceMatrix(String value). verify that
+   * matrix parameter is updated accordingly
+   */
+  @Test
+  public void replaceMatrixTest3() throws Fault {
+    String expected = "http://localhost:8080;name1=x;name1=y;name1=y%20x;name1=x%25y;name1=%20";
+    String value = "name1=x;name1=y;name1=y x;name1=x%y;name1= ";
+
+    try {
+      uri = UriBuilder
+          .fromPath("http://localhost:8080;name=x=;name=y?;name=x y;name=&")
+          .replaceMatrix(value).build();
+      gotExpectedPass(uri.toString(), expected);
+    } catch (Exception ex) {
+      pass = false;
+      sb.append("Unexpected Exception thrown" + ex.getMessage());
+    }
+
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: userInfoTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:231;
+   * 
+   * @test_Strategy: call UriBuilder.userInfo in different states of UriBuilder
+   * Check the userInfo on built java.net.URI
+   */
+  @Test
+  public void userInfoTest() throws Fault {
+    String unexpected = "Unexpected user info:";
+    String userInfo = "foo:foo";
+
+    uri = UriBuilder.fromUri(LOCALHOST).build();
+    assertTrue(uri.getUserInfo() == null, unexpected+ uri.getUserInfo());
+
+    uri = UriBuilder.fromUri(LOCALHOST).userInfo(userInfo).build();
+    assertTrue(uri.getRawUserInfo().equals(userInfo), unexpected+
+        uri.getRawUserInfo());
+    System.out.println(uri.getRawUserInfo());
+
+    uri = UriBuilder.fromUri("http://foo2:foo2@localhost:8080")
+        .userInfo(userInfo).build();
+    System.out.println(uri.getRawUserInfo());
+    assertTrue(userInfo.equals(uri.getRawUserInfo()), unexpected+
+        uri.getRawUserInfo());
+
+    uri = UriBuilder.fromPath("").scheme("http").userInfo(userInfo)
+        .host("localhost").port(8080).build();
+    assertTrue(uri.getRawUserInfo().equals(userInfo), unexpected+
+        uri.getRawUserInfo());
+  }
+
+  /*
+   * @testName: buildObjectsBooleanEncodedTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:886;
+   * 
+   * @test_Strategy: Build a URI, using the supplied values in order to replace
+   * any URI template parameters. Values are converted to String using their
+   * toString() method and are then encoded to match the rules of the URI
+   * component to which they pertain. The slash ('/') characters in parameter
+   * values will be encoded if the template is placed in the URI path component.
+   */
+  @Test
+  public void buildObjectsBooleanEncodedTest() throws Fault {
+    Object s[] = { "path-rootless/test2", new StringBuilder("x%yz"),
+        "/path-absolute/%25test1", "fred@example.com" };
+    uri = UriBuilder.fromPath("").path("{v}/{w}/{x}/{y}/{w}")
+        .build(new Object[] { s[0], s[1], s[2], s[3], s[1] }, true);
+    gotExpectedPass(uri.getRawPath(), ENCODED_EXPECTED_PATH);
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: buildObjectsBooleanNotEncodedTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:886;
+   * 
+   * @test_Strategy: Build a URI, using the supplied values in order to replace
+   * any URI template parameters. Values are converted to String using their
+   * toString() method and are then encoded to match the rules of the URI
+   * component to which they pertain.
+   */
+  @Test
+  public void buildObjectsBooleanNotEncodedTest() throws Fault {
+    Object s[] = { new StringBuffer("path-rootless/test2"), "x%yz",
+        "/path-absolute", "test1", "fred@example.com" };
+    uri = UriBuilder.fromPath("").path("{v}/{w}/{x}/{y}/{z}/{w}")
+        .build(new Object[] { s[0], s[1], s[2], s[3], s[4], s[1] }, false);
+    gotExpectedPass(uri.getRawPath(), EXPECTED_PATH);
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: buildObjectsBooleanThrowsIAEWhenNoValueSuppliedTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:887;
+   * 
+   * @test_Strategy: java.lang.IllegalArgumentException - if there are any URI
+   * template parameters without a supplied value
+   */
+  @Test
+  public void buildObjectsBooleanThrowsIAEWhenNoValueSuppliedTest()
+      throws Fault {
+    try {
+      uri = UriBuilder.fromPath("").path("{v}/{w}")
+          .build(new Object[] { "first" }, false);
+      fault("IllegalArgumentException has not been thrown, uri:", uri);
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been thrown as expected", e);
+    }
+  }
+
+  /*
+   * @testName: buildObjectsBooleanThrowsIAEWhenValueIsNullTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:887;
+   * 
+   * @test_Strategy: java.lang.IllegalArgumentException - if a value is null.
+   */
+  @Test
+  public void buildObjectsBooleanThrowsIAEWhenValueIsNullTest() throws Fault {
+    try {
+      uri = UriBuilder.fromPath("").path("{v}/{w}")
+          .build(new Object[] { "first", null }, false);
+      fault("IllegalArgumentException has not been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been thrown as expected", e);
+    }
+  }
+
+  /*
+   * @testName: buildFromMapWithBooleanSlashEncodedTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:889;
+   * 
+   * @test_Strategy: Build a URI. Any URI template parameters will be replaced
+   * by the value in the supplied map. Values are converted to String using
+   * their toString() method and are then encoded to match the rules of the URI
+   * component to which they pertain. All '%' characters in the stringified
+   * values will be encoded. The state of the builder is unaffected; this method
+   * may be called multiple times on the same builder instance. The slash ('/')
+   * characters in parameter values will be encoded if the template is placed in
+   * the URI path component.
+   */
+  @Test
+  public void buildFromMapWithBooleanSlashEncodedTest() throws Fault {
+    Map<String, Object> map = new HashMap<String, Object>();
+    map.put("x", new StringBuilder("x%yz"));
+    map.put("y", new StringBuffer("/path-absolute/%25test1"));
+    map.put("z", new Object() {
+      public String toString() {
+        return "fred@example.com";
+      }
+    });
+    map.put("w", "path-rootless/test2");
+    UriBuilder builder = UriBuilder.fromPath("").path("{w}/{x}/{y}/{z}/{x}");
+    builder.buildFromMap(map, false); // can be called multiple times
+    uri = builder.buildFromMap(map, true);
+    gotExpectedPass(uri.getRawPath(), ENCODED_EXPECTED_PATH);
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: buildFromMapWithBooleanSlashNotEncodedTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:889;
+   * 
+   * @test_Strategy: Build a URI. Any URI template parameters will be replaced
+   * by the value in the supplied map. Values are converted to String using
+   * their toString() method and are then encoded to match the rules of the URI
+   * component to which they pertain. All '%' characters in the stringified
+   * values will be encoded. The state of the builder is unaffected; this method
+   * may be called multiple times on the same builder instance.
+   */
+  @Test
+  public void buildFromMapWithBooleanSlashNotEncodedTest() throws Fault {
+    Map<String, Object> map = new HashMap<String, Object>();
+    map.put("x", new StringBuilder("x%yz"));
+    map.put("y", new StringBuffer("/path-absolute/test1"));
+    map.put("z", new Object() {
+      public String toString() {
+        return "fred@example.com";
+      }
+    });
+    map.put("w", "path-rootless/test2");
+    UriBuilder builder = UriBuilder.fromPath("").path("{w}/{x}/{y}/{z}/{x}");
+    uri = builder.buildFromMap(map, false);
+    gotExpectedPass(uri.getRawPath(), EXPECTED_PATH);
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: buildFromMapWithBooleanThrowsIAEWhenNoSuppliedValueTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:890;
+   * 
+   * @test_Strategy: java.lang.IllegalArgumentException - if there are any URI
+   * template parameters without a supplied value
+   */
+  @Test
+  public void buildFromMapWithBooleanThrowsIAEWhenNoSuppliedValueTest()
+      throws Fault {
+    Map<String, Object> map = new HashMap<String, Object>();
+    map.put("x", new StringBuilder("x%yz"));
+    map.put("y", new StringBuffer("/path-absolute/test1"));
+    map.put("w", "path-rootless/test2");
+    UriBuilder builder = UriBuilder.fromPath("").path("{w}/{x}/{y}/{z}/{x}");
+    try {
+      uri = builder.buildFromMap(map, false);
+      fault("No exception has been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been thrown as expected");
+    }
+  }
+
+  /*
+   * @testName: buildFromMapWithBooleanThrowsIAEWhenNullValueTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:890;
+   * 
+   * @test_Strategy: java.lang.IllegalArgumentException - if a template
+   * parameter value is null.
+   */
+  @Test
+  public void buildFromMapWithBooleanThrowsIAEWhenNullValueTest() throws Fault {
+    Map<String, Object> map = new HashMap<String, Object>();
+    map.put("x", new StringBuilder("x%yz"));
+    map.put("y", new StringBuffer("/path-absolute/test1"));
+    map.put("z", null);
+    map.put("w", "path-rootless/test2");
+    UriBuilder builder = UriBuilder.fromPath("").path("{w}/{x}/{y}/{z}/{x}");
+    try {
+      uri = builder.buildFromMap(map, false);
+      fault("No exception has been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been thrown as expected");
+    }
+  }
+
+  /*
+   * @testName: fromLinkTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:892;
+   * 
+   * @test_Strategy: Create a new instance initialized from a Link.
+   */
+  @Test
+  public void fromLinkTest() throws Fault {
+    URI uri = UriBuilder.fromUri(LOCALHOST).build();
+    Link link = Link.fromUri(uri).build();
+    URI uri2 = UriBuilder.fromLink(link).build();
+    assertTrue(uri.equals(uri2), "URI"+ uri+ "and"+ uri2+ "are not equal");
+    logMsg("URI fromLink is equal to the expected URI");
+  }
+
+  /*
+   * @testName: fromLinkThrowsIllegalArgumentExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:892;
+   * 
+   * @test_Strategy: throws IllegalArgumentException - if link is {@code null}
+   */
+  @Test
+  public void fromLinkThrowsIllegalArgumentExceptionTest() throws Fault {
+    try {
+      UriBuilder.fromLink((Link) null);
+      throw new Fault("IllegalArgumentException has not been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been thrown as expected");
+    }
+  }
+
+  /*
+   * @testName: fromMethodTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:894;
+   * 
+   * @test_Strategy: Create a new instance representing a relative URI
+   * initialized from a Path-annotated method. This method can only be used in
+   * cases where there is a single method with the specified name that is
+   * annotated with Path.
+   */
+  @Test
+  public void fromMethodTest() throws Fault {
+    URI uri = UriBuilder.fromMethod(TestPath.class, "headSub").build();
+    assertTrue(uri.toASCIIString().equals("/sub"),
+        "There is no /sub in the URI");
+    logMsg("URI fromMethod is equal to the expected URI", uri);
+  }
+
+  /*
+   * @testName: fromMethodThrowsIllegalArgumentExceptionWhenMorePathsTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:894;
+   * 
+   * @test_Strategy: Throws: IllegalArgumentException - if resource or method is
+   * null, or there is more than or less than one variant of the method
+   * annotated with Path.
+   */
+  @Test
+  public void fromMethodThrowsIllegalArgumentExceptionWhenMorePathsTest()
+      throws Fault {
+    try {
+      UriBuilder.fromMethod(TestPath.class, "test1");
+      throw new Fault("IllegalArgumentException has not been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been sucessfully thrown", e);
+    }
+  }
+
+  /*
+   * @testName: fromMethodThrowsIllegalArgumentExceptionWhenNoPathTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:894;
+   * 
+   * @test_Strategy: Throws: IllegalArgumentException - if resource or method is
+   * null, or there is more than or less than one variant of the method
+   * annotated with Path.
+   */
+  @Test
+  public void fromMethodThrowsIllegalArgumentExceptionWhenNoPathTest()
+      throws Fault {
+    try {
+      UriBuilder.fromMethod(TestPath.class, "getPlain");
+      throw new Fault("IllegalArgumentException has not been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been sucessfully thrown", e);
+    }
+  }
+
+  /*
+   * @testName: toTemplateTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:896;
+   * 
+   * @test_Strategy: Get the URI template string represented by this URI
+   * builder.
+   */
+  @Test
+  public void toTemplateTest() throws Fault {
+    String template = "{v}/{w}/{x}/{y}/{w}";
+    UriBuilder builder = UriBuilder.fromPath("").path(template);
+    assertEquals(template, builder.toTemplate(), "Given template", template,
+        "differs from obtain", builder.toTemplate());
+    logMsg("Got expected template", template);
+  }
+
+  /*
+   * @testName: uriStringTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:897;
+   * 
+   * @test_Strategy: Parses the string and copies the parsed components of the
+   * supplied URI to the UriBuilder replacing any existing values for those
+   * components.
+   */
+  @Test
+  public void uriStringTest() throws Fault {
+    String origUris[] = getOrigUris();
+    URI[] replaceUris = getReplacementUris();
+    String[] expectUris = getExpectedUris();
+
+    int cnt = 0;
+    int failed = 0;
+    int passed = 0;
+    while (cnt < 17) {
+      try {
+        sb.append("Replace uri ").append(origUris[cnt]).append(" with ")
+            .append(replaceUris[cnt].toASCIIString()).append(newline);
+        uri = UriBuilder.fromUri(new URI(origUris[cnt]))
+            .uri(replaceUris[cnt].toASCIIString()).build();
+        if (gotExpectedPass(uri.toString().trim(), expectUris[cnt]) != 0)
+          failed++;
+        else
+          passed++;
+      } catch (Exception ex) {
+        pass = false;
+        sb.append("Unexpected exception thrown: ").append(ex.getMessage())
+            .append(newline);
+        sb.append("Test failed with exception for expected uri: ")
+            .append(expectUris[cnt]).append(newline);
+        failed++;
+      }
+      cnt++;
+    }
+
+    assertTrue(pass, passed+ "assertion passed."+ newline+ failed+
+        "assertion(s) failed:"+ sb.toString()+ newline);
+  }
+
+  /*
+   * @testName: uriStringThrowsIAEWhenNullTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:896;
+   * 
+   * @test_Strategy: throws IllegalArgumentException - if URI template or is
+   * {@code null}.
+   */
+  @Test
+  public void uriStringThrowsIAEWhenNullTest() throws Fault {
+    try {
+      UriBuilder.fromMethod(TestPath.class, "headSub").uri((String) null);
+      throw new Fault("No Exception has been thrown for #uri(null)");
+    } catch (IllegalArgumentException e) {
+      logMsg(
+          "#IllegalArgumentException has been thrown as expected for #uri(null)");
+    }
+  }
+
+  /*
+   * @testName: uriStringThrowsIAEWhenNoUriTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:896;
+   * 
+   * @test_Strategy: throws IllegalArgumentException - if {@code uriTemplate} is
+   * not a valid URI template
+   */
+  @Test
+  public void uriStringThrowsIAEWhenNoUriTest() throws Fault {
+    String sUri = "://";
+    try {
+      uri = UriBuilder.fromUri(new URI("news//:comp.lang.java")).uri(sUri)
+          .build();
+      fault("No Exception has been thrown for #uri(noURI)", uri);
+    } catch (IllegalArgumentException e) {
+      logMsg(
+          "#IllegalArgumentException has been thrown as expected for #uri(noURI)");
+    } catch (URISyntaxException e) {
+      throw new Fault(e);
+    }
+  }
+
+  /*
+   * @testName: resolveTemplateStringObjectTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:957;
+   * 
+   * @test_Strategy: Resolve a URI template with a given name in this UriBuilder
+   * instance using a supplied value
+   */
+  @Test
+  public void resolveTemplateStringObjectTest() throws Fault {
+    String template = "{v}/{w}/{x}/{y}/{w}";
+    UriBuilder builder = UriBuilder.fromPath("").path(template)
+        .resolveTemplate("v", new StringBuilder("aaa"));
+    String resolvedTemplate = template.replace("{v}", "aaa");
+    String builderTemplate = builder.toTemplate();
+    assertEquals(resolvedTemplate, builderTemplate, "Given template", template,
+        "was not resolved correctly, remains", builderTemplate);
+    logMsg("Got expected template", template);
+  }
+
+  /*
+   * @testName: resolveTemplateStringObjectThrowsIAEOnNullNameTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:957;
+   * 
+   * @test_Strategy: if the resolved template name or value is null.
+   */
+  @Test
+  public void resolveTemplateStringObjectThrowsIAEOnNullNameTest()
+      throws Fault {
+    String template = "{v}/{w}/{x}/{y}/{w}";
+    UriBuilder builder = UriBuilder.fromPath("").path(template);
+    try {
+      builder.resolveTemplate(null, "aaa");
+      fault("No exception has been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been thrown as expected", e);
+    }
+  }
+
+  /*
+   * @testName: resolveTemplateStringObjectThrowsIAEOnNullValueTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:957;
+   * 
+   * @test_Strategy: if the resolved template name or value is null.
+   */
+  @Test
+  public void resolveTemplateStringObjectThrowsIAEOnNullValueTest()
+      throws Fault {
+    String template = "{v}/{w}/{x}/{y}/{w}";
+    UriBuilder builder = UriBuilder.fromPath("").path(template);
+    try {
+      builder.resolveTemplate("v", null);
+      fault("No exception has been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been thrown as expected", e);
+    }
+  }
+
+  /*
+   * @testName: resolveTemplateStringObjectBooleanSlashEncodedTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:959;
+   * 
+   * @test_Strategy: Resolve a URI template with a given name in this UriBuilder
+   * instance using a supplied value. The slash ('/') characters in template
+   * values will be encoded.
+   */
+  @Test
+  public void resolveTemplateStringObjectBooleanSlashEncodedTest()
+      throws Fault {
+    String template = "{v}/{w}/{x}/{y}/{w}";
+    UriBuilder builder = UriBuilder.fromPath("").path(template)
+        .resolveTemplate("v", new StringBuilder("a/a/a"), true);
+    String resolvedTemplate = template.replace("{v}", "a%2Fa%2Fa");
+    String builderTemplate = builder.toTemplate().replace("%2f", "%2F");
+    assertEquals(resolvedTemplate, builderTemplate, "Given template", template,
+        "was not resolved correctly, remains", builderTemplate);
+    logMsg("Got expected template", template);
+  }
+
+  /*
+   * @testName: resolveTemplateStringObjectBooleanSlashNotEncodedTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:959;
+   * 
+   * @test_Strategy: Resolve a URI template with a given name in this UriBuilder
+   * instance using a supplied value.
+   */
+  @Test
+  public void resolveTemplateStringObjectBooleanSlashNotEncodedTest()
+      throws Fault {
+    String template = "{v}/{w}/{x}/{y}/{w}";
+    UriBuilder builder = UriBuilder.fromPath("").path(template)
+        .resolveTemplate("v", new StringBuilder("a/a/a"), false);
+    String resolvedTemplate = template.replace("{v}", "a/a/a");
+    String builderTemplate = builder.toTemplate();
+    assertEquals(resolvedTemplate, builderTemplate, "Given template", template,
+        "was not resolved correctly, remains", builderTemplate);
+    logMsg("Got expected template", template);
+  }
+
+  /*
+   * @testName: resolveTemplateStringObjectBooleanThrowsIAEOnNullNameTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:959;
+   * 
+   * @test_Strategy: if the resolved template name or value is null.
+   */
+  @Test
+  public void resolveTemplateStringObjectBooleanThrowsIAEOnNullNameTest()
+      throws Fault {
+    String template = "{v}/{w}/{x}/{y}/{w}";
+    UriBuilder builder = UriBuilder.fromPath("").path(template);
+    try {
+      builder.resolveTemplate(null, "aaa", false);
+      fault("No exception has been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been thrown as expected", e);
+    }
+  }
+
+  /*
+   * @testName: resolveTemplateStringObjectBooleanThrowsIAEOnNullValueTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:959;
+   * 
+   * @test_Strategy: if the resolved template name or value is null.
+   */
+  @Test
+  public void resolveTemplateStringObjectBooleanThrowsIAEOnNullValueTest()
+      throws Fault {
+    String template = "{v}/{w}/{x}/{y}/{w}";
+    UriBuilder builder = UriBuilder.fromPath("").path(template);
+    try {
+      builder.resolveTemplate("v", null, false);
+      fault("No exception has been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been thrown as expected", e);
+    }
+  }
+
+  /*
+   * @testName: resolveTemplateFromEncodedTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:961;
+   * 
+   * @test_Strategy: Resolve a URI template with a given name in this UriBuilder
+   * instance using a supplied encoded value.
+   */
+  @Test
+  public void resolveTemplateFromEncodedTest() throws Fault {
+    Object s[] = { "path-rootless%2Ftest2", new StringBuilder("x%25yz"),
+        "%2Fpath-absolute%2F%2525test1", "fred@example.com" };
+    UriBuilder builder = UriBuilder.fromPath("").path("{v}/{w}/{x}/{y}/{w}");
+    builder = builder.resolveTemplateFromEncoded("v", s[0]);
+    builder = builder.resolveTemplateFromEncoded("w", s[1]);
+    builder = builder.resolveTemplateFromEncoded("x", s[2]);
+    builder = builder.resolveTemplateFromEncoded("y", s[3]);
+    uri = builder.build();
+    gotExpectedPass(uri.getRawPath(), ENCODED_EXPECTED_PATH);
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: resolveTemplateFromEncodedPercentEncodedTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:961;
+   * 
+   * @test_Strategy: Resolve a URI template with a given name in this UriBuilder
+   * instance using a supplied encoded value. All % characters in the
+   * stringified values that are not followed by two hexadecimal numbers will be
+   * encoded.
+   */
+  @Test
+  public void resolveTemplateFromEncodedPercentEncodedTest() throws Fault {
+    Object s[] = { "path-rootless%2Ftest2", new StringBuilder("x%yz"),
+        "%2Fpath-absolute%2F%2525test1", "fred@example.com" };
+    UriBuilder builder = UriBuilder.fromPath("").path("{v}/{w}/{x}/{y}/{w}");
+    builder = builder.resolveTemplateFromEncoded("v", s[0]);
+    builder = builder.resolveTemplateFromEncoded("w", s[1]);
+    builder = builder.resolveTemplateFromEncoded("x", s[2]);
+    builder = builder.resolveTemplateFromEncoded("y", s[3]);
+    uri = builder.build();
+    gotExpectedPass(uri.getRawPath(), ENCODED_EXPECTED_PATH);
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: resolveTemplateFromEncodedThrowsNullOnNullNameTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:961;
+   * 
+   * @test_Strategy: java.lang.IllegalArgumentException - if the resolved
+   * template name or encoded value is null.
+   */
+  @Test
+  public void resolveTemplateFromEncodedThrowsNullOnNullNameTest()
+      throws Fault {
+    Object s[] = { "path-rootless%2Ftest2", new StringBuilder("x%25yz"),
+        "%2Fpath-absolute%2F%2525test1", "fred@example.com" };
+    UriBuilder builder = UriBuilder.fromPath("").path("{v}/{w}/{x}/{y}/{w}");
+    try {
+      builder.resolveTemplateFromEncoded(null, s[0]);
+      fault("No exception has been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException thrown as expected", e);
+    }
+  }
+
+  /*
+   * @testName: resolveTemplateFromEncodedThrowsNullOnNullValueTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:961;
+   * 
+   * @test_Strategy: java.lang.IllegalArgumentException - if the resolved
+   * template name or encoded value is null.
+   */
+  @Test
+  public void resolveTemplateFromEncodedThrowsNullOnNullValueTest()
+      throws Fault {
+    UriBuilder builder = UriBuilder.fromPath("").path("{v}/{w}/{x}/{y}/{w}");
+    try {
+      builder.resolveTemplateFromEncoded("v", (Object) null);
+      fault("No exception has been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException thrown as expected", e);
+    }
+  }
+
+  /*
+   * @testName: resolveTemplatesMapTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:963;
+   * 
+   * @test_Strategy: Resolve one or more URI templates in this UriBuilder
+   * instance using supplied name-value pairs.
+   */
+  @Test
+  public void resolveTemplatesMapTest() throws Fault {
+    Map<String, Object> map = new HashMap<String, Object>();
+    map.put("x", new StringBuilder("x%yz"));
+    map.put("y", new StringBuffer("/path-absolute/%25test1"));
+    map.put("z", new Object() {
+      public String toString() {
+        return "fred@example.com";
+      }
+    });
+    map.put("w", "path-rootless/test2");
+    UriBuilder builder = UriBuilder.fromPath("").path("{w}/{x}/{y}/{z}/{x}");
+    uri = builder.resolveTemplates(map).build();
+    gotExpectedPass(uri.getRawPath(), ENCODED_EXPECTED_PATH);
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: resolveTemplatesMapThrowsIAEOnNullNameTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:963;
+   * 
+   * @test_Strategy:java.lang.IllegalArgumentException - if the name-value map
+   * or any of the names or values in the map is null.
+   */
+  @Test
+  public void resolveTemplatesMapThrowsIAEOnNullNameTest() throws Fault {
+    Map<String, Object> map = new HashMap<String, Object>();
+    map.put("a", new StringBuilder("x%yz"));
+    map.put(null, "path-rootless/test2");
+    UriBuilder builder = UriBuilder.fromPath("").path("{a}/{b}");
+    try {
+      builder.resolveTemplates(map);
+      fault("IllegalArgumentException has not been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been thrown as expected", e);
+    }
+  }
+
+  /*
+   * @testName: resolveTemplatesMapThrowsIAEOnNullValueTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:963;
+   * 
+   * @test_Strategy:java.lang.IllegalArgumentException - if the name-value map
+   * or any of the names or values in the map is null.
+   */
+  @Test
+  public void resolveTemplatesMapThrowsIAEOnNullValueTest() throws Fault {
+    Map<String, Object> map = new HashMap<String, Object>();
+    map.put("a", null);
+    map.put("b", "path-rootless/test2");
+    UriBuilder builder = UriBuilder.fromPath("").path("{a}/{b}");
+    try {
+      builder.resolveTemplates(map);
+      fault("IllegalArgumentException has not been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been thrown as expected", e);
+    }
+  }
+
+  /*
+   * @testName: resolveTemplatesMapBooleanSlashEncodedTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:965;
+   * 
+   * @test_Strategy: Resolve one or more URI templates in this UriBuilder
+   * instance using supplied name-value pairs.
+   */
+  @Test
+  public void resolveTemplatesMapBooleanSlashEncodedTest() throws Fault {
+    Map<String, Object> map = new HashMap<String, Object>();
+    map.put("x", new StringBuilder("x%yz"));
+    map.put("y", new StringBuffer("/path-absolute/%25test1"));
+    map.put("z", new Object() {
+      public String toString() {
+        return "fred@example.com";
+      }
+    });
+    map.put("w", "path-rootless/test2");
+    UriBuilder builder = UriBuilder.fromPath("").path("{w}/{x}/{y}/{z}/{x}");
+    uri = builder.resolveTemplates(map, true).build();
+    gotExpectedPass(uri.getRawPath(), ENCODED_EXPECTED_PATH);
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: resolveTemplatesMapBooleanSlashNotEncodedTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:965;
+   * 
+   * @test_Strategy: Resolve one or more URI templates in this UriBuilder
+   * instance using supplied name-value pairs.
+   */
+  @Test
+  public void resolveTemplatesMapBooleanSlashNotEncodedTest() throws Fault {
+    Map<String, Object> map = new HashMap<String, Object>();
+    map.put("x", new StringBuilder("x%yz"));
+    map.put("y", new StringBuffer("/path-absolute/test1"));
+    map.put("z", new Object() {
+      public String toString() {
+        return "fred@example.com";
+      }
+    });
+    map.put("w", "path-rootless/test2");
+    UriBuilder builder = UriBuilder.fromPath("").path("{w}/{x}/{y}/{z}/{x}");
+    uri = builder.resolveTemplates(map, false).build();
+    gotExpectedPass(uri.getRawPath(), EXPECTED_PATH);
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: resolveTemplatesMapBooleanThrowsIAEOnNullNameTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:966;
+   * 
+   * @test_Strategy:java.lang.IllegalArgumentException - if the name-value map
+   * or any of the names or values in the map is null.
+   */
+  @Test
+  public void resolveTemplatesMapBooleanThrowsIAEOnNullNameTest() throws Fault {
+    Map<String, Object> map = new HashMap<String, Object>();
+    map.put("a", new StringBuilder("x%yz"));
+    map.put(null, "path-rootless/test2");
+    UriBuilder builder = UriBuilder.fromPath("").path("{a}/{b}");
+    try {
+      builder.resolveTemplates(map, true);
+      fault("IllegalArgumentException has not been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been thrown as expected", e);
+    }
+  }
+
+  /*
+   * @testName: resolveTemplatesMapBooleanThrowsIAEOnNullValueTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:966;
+   * 
+   * @test_Strategy:java.lang.IllegalArgumentException - if the name-value map
+   * or any of the names or values in the map is null.
+   */
+  @Test
+  public void resolveTemplatesMapBooleanThrowsIAEOnNullValueTest()
+      throws Fault {
+    Map<String, Object> map = new HashMap<String, Object>();
+    map.put("a", null);
+    map.put("b", "path-rootless/test2");
+    UriBuilder builder = UriBuilder.fromPath("").path("{a}/{b}");
+    try {
+      builder.resolveTemplates(map, false);
+      fault("IllegalArgumentException has not been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been thrown as expected", e);
+    }
+  }
+
+  /*
+   * @testName: resolveTemplatesMapBooleanThrowsIAEOnNullMapTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:966;
+   * 
+   * @test_Strategy:java.lang.IllegalArgumentException - if the name-value map
+   * or any of the names or values in the map is null.
+   */
+  @Test
+  public void resolveTemplatesMapBooleanThrowsIAEOnNullMapTest() throws Fault {
+    UriBuilder builder = UriBuilder.fromPath("").path("{a}/{b}");
+    try {
+      builder.resolveTemplates((Map<String, Object>) null, false);
+      fault("IllegalArgumentException has not been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException has been thrown as expected", e);
+    }
+  }
+
+  /*
+   * @testName: resolveTemplatesFromEncodedTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:967;
+   * 
+   * @test_Strategy: Resolve one or more URI templates in this instance using
+   * supplied name-value pairs.
+   */
+  @Test
+  public void resolveTemplatesFromEncodedTest() throws Fault {
+    Map<String, Object> map = new HashMap<String, Object>();
+    map.put("v", new StringBuilder("path-rootless%2Ftest2"));
+    map.put("w", new StringBuilder("x%25yz"));
+    map.put("x", new Object() {
+      public String toString() {
+        return "%2Fpath-absolute%2F%2525test1";
+      }
+    });
+    map.put("y", "fred@example.com");
+    UriBuilder builder = UriBuilder.fromPath("").path("{v}/{w}/{x}/{y}/{w}");
+    builder = builder.resolveTemplatesFromEncoded(map);
+    uri = builder.build();
+    gotExpectedPass(uri.getRawPath(), ENCODED_EXPECTED_PATH);
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: resolveTemplatesFromEncodedPercentEncodedTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:967;
+   * 
+   * @test_Strategy: Resolve one or more URI templates in this instance using
+   * supplied name-value pairs. All % characters in the stringified values that
+   * are not followed by two hexadecimal numbers will be encoded.
+   */
+  @Test
+  public void resolveTemplatesFromEncodedPercentEncodedTest() throws Fault {
+    Map<String, Object> map = new HashMap<String, Object>();
+    map.put("v", new StringBuilder("path-rootless%2Ftest2"));
+    map.put("w", new StringBuilder("x%yz"));
+    map.put("x", new Object() {
+      public String toString() {
+        return "%2Fpath-absolute%2F%2525test1";
+      }
+    });
+    map.put("y", "fred@example.com");
+    UriBuilder builder = UriBuilder.fromPath("").path("{v}/{w}/{x}/{y}/{w}");
+    builder = builder.resolveTemplatesFromEncoded(map);
+    uri = builder.build();
+    gotExpectedPass(uri.getRawPath(), ENCODED_EXPECTED_PATH);
+    assertPassAndLog();
+  }
+
+  /*
+   * @testName: resolveTemplatesFromEncodedThrowsNullOnNullNameTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:967;
+   * 
+   * @test_Strategy: java.lang.IllegalArgumentException - if the name-value map
+   * or any of the names or values in the map is null.
+   */
+  @Test
+  public void resolveTemplatesFromEncodedThrowsNullOnNullNameTest()
+      throws Fault {
+    Map<String, Object> map = new HashMap<String, Object>();
+    map.put(null, "aa");
+    UriBuilder builder = UriBuilder.fromPath("").path("{v}/{w}/{x}/{y}/{w}");
+    try {
+      builder.resolveTemplatesFromEncoded(map);
+      fault("No exception has been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException thrown as expected", e);
+    }
+  }
+
+  /*
+   * @testName: resolveTemplatesFromEncodedThrowsNullOnNullValueTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:967;
+   * 
+   * @test_Strategy: java.lang.IllegalArgumentException - if the name-value map
+   * or any of the names or values in the map is null.
+   */
+  @Test
+  public void resolveTemplatesFromEncodedThrowsNullOnNullValueTest()
+      throws Fault {
+    Map<String, Object> map = new HashMap<String, Object>();
+    map.put("v", null);
+    UriBuilder builder = UriBuilder.fromPath("").path("{v}/{w}/{x}/{y}/{w}");
+    try {
+      builder.resolveTemplatesFromEncoded(map);
+      fault("No exception has been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException thrown as expected", e);
+    }
+  }
+
+  /*
+   * @testName: resolveTemplatesFromEncodedThrowsNullOnNullMapTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:967;
+   * 
+   * @test_Strategy: java.lang.IllegalArgumentException - if the name-value map
+   * or any of the names or values in the map is null.
+   */
+  @Test
+  public void resolveTemplatesFromEncodedThrowsNullOnNullMapTest()
+      throws Fault {
+    UriBuilder builder = UriBuilder.fromPath("").path("{v}/{w}/{x}/{y}/{w}");
+    try {
+      builder.resolveTemplatesFromEncoded((Map<String, Object>) null);
+      fault("No exception has been thrown");
+    } catch (IllegalArgumentException e) {
+      logMsg("IllegalArgumentException thrown as expected", e);
+    }
+  }
+
+
+  // ////////////////////////////////////////////////////////////////////////
+  /**
+   * This is the pattern used in all over the tests. Add to stringBuilder what's
+   * expected, what's got and set pass value.
+   * 
+   * @param got
+   * @param expected
+   * @return got.compareToIgnoreCase(expected)
+   */
+  private int gotExpectedPass(String got, String expected) {
+    got = got.replace("%2f", "%2F");
+    int compare = got.compareToIgnoreCase(expected);
+    gotExpectedPass(compare != 0, got, expected);
+    return compare;
+  }
+
+  private boolean gotExpectedPass(boolean conditionFalse, String got,
+      String expected) {
+    if (conditionFalse) {
+      pass = false;
+      sb.append("Incorrect URI returned: ").append(got);
+      sb.append(", expecting ").append(expected);
+    } else
+      sb.append("Got expected return: ").append(expected);
+    sb.append(newline);
+    return conditionFalse;
+
+  }
+
+  private void assertPassAndLog() throws Fault {
+    assertTrue(pass, "At least one assertion failed:"+ sb.toString());    
+    TestUtil.logTrace(sb.toString());
+  }
+
+  private static String[] getOrigUris() {
+    String[] uris_orig = { "ftp://ftp.is.co.za/rfc/rfc1808.txt",
+        "ftp://ftp.is.co.za/rfc/rfc1808.txt", "mailto:java-net@java.sun.com",
+        "mailto:java-net@java.sun.com", "news:comp.lang.java",
+        "news:comp.lang.java", "urn:isbn:096139210x",
+        "http://www.ietf.org/rfc/rfc2396.txt",
+        "http://www.ietf.org/rfc/rfc2396.txt",
+        "ldap://[2001:db8::7]/c=GB?objectClass?one",
+        "ldap://[2001:db8::7]/c=GB?objectClass?one", "tel:+1-816-555-1212",
+        "tel:+1-816-555-1212", "telnet://192.0.2.16:80/",
+        "telnet://192.0.2.16:80/",
+        "foo://example.com:8042/over/there?name=ferret#nose",
+        "foo://example.com:8042/over/there?name=ferret#nose" };
+    return uris_orig;
+  }
+
+  private static URI[] getReplacementUris() throws Fault {
+    URI uris_replace[] = { null, null, null, null, null, null, null, null, null,
+        null, null, null, null, null, null, null, null };
+
+    try {
+      uris_replace[0] = new URI("http", "//ftp.is.co.za/rfc/rfc1808.txt", null);
+      uris_replace[1] = new URI(null, "ftp.is.co.za", "/test/rfc1808.txt", null,
+          null);
+      uris_replace[2] = new URI("mailto", "java-net@java.sun.com", null);
+      uris_replace[3] = new URI(null, "testuser@sun.com", null);
+      uris_replace[4] = new URI("http", "//comp.lang.java", null);
+      uris_replace[5] = new URI(null, "news.lang.java", null);
+      uris_replace[6] = new URI("urn:isbn:096139210x");
+      uris_replace[7] = new URI(null, "//www.ietf.org/rfc/rfc2396.txt", null);
+      uris_replace[8] = new URI(null, "www.ietf.org", "/rfc/rfc2396.txt", null,
+          null);
+      uris_replace[9] = new URI("ldap", "//[2001:db8::7]/c=GB?objectClass?one",
+          null);
+      uris_replace[10] = new URI(null, "//[2001:db8::7]/c=GB?objectClass?one",
+          null);
+      uris_replace[11] = new URI("tel", "+1-816-555-1212", null);
+      uris_replace[12] = new URI(null, "+1-866-555-1212", null);
+      uris_replace[13] = new URI("telnet", "//192.0.2.16:80/", null);
+      uris_replace[14] = new URI(null, "//192.0.2.16:81/", null);
+      uris_replace[15] = new URI("http",
+          "//example.com:8042/over/there?name=ferret", null);
+      uris_replace[16] = new URI(null,
+          "//example.com:8042/over/there?name=ferret", "mouth");
+    } catch (Exception ex) {
+      throw new Fault(
+          "========== Exception thrown constructing replacing URIs: "
+              + ex.getMessage() + newline);
+    }
+    return uris_replace;
+  }
+
+  private static String[] getExpectedUris() {
+    String[] uris_expect = { "http://ftp.is.co.za/rfc/rfc1808.txt",
+        "ftp://ftp.is.co.za/test/rfc1808.txt", "mailto:java-net@java.sun.com",
+        "mailto:testuser@sun.com", "http://comp.lang.java",
+        "news:news.lang.java", "urn:isbn:096139210x",
+        "http://www.ietf.org/rfc/rfc2396.txt",
+        "http://www.ietf.org/rfc/rfc2396.txt",
+        "ldap://[2001:db8::7]/c=GB?objectClass?one",
+        "ldap://[2001:db8::7]/c=GB?objectClass?one", "tel:+1-816-555-1212",
+        "tel:+1-866-555-1212", "telnet://192.0.2.16:80/",
+        "telnet://192.0.2.16:81/",
+        "http://example.com:8042/over/there?name=ferret#nose",
+        "foo://example.com:8042/over/there?name=ferret#mouth" };
+    return uris_expect;
+  }
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/uribuilder/TestPath.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/uribuilder/TestPath.java
new file mode 100644
index 0000000..fbfbca0
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/uribuilder/TestPath.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.api.rs.core.uribuilder;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.Response;
+
+@Path(value = "/TestPath")
+public class TestPath {
+
+  @GET
+  public Response getPlain() {
+    return Response.ok().build();
+  }
+
+  @Path(value = "/sub")
+  public Response headSub() {
+    return Response.ok().build();
+  }
+
+  @Path(value = "sub1")
+  public Response test1() {
+    return Response.ok().build();
+  }
+
+  @Path(value = "/sub2")
+  public Response test1(@QueryParam("testName") String test) {
+    return Response.ok(test).build();
+  }
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/uribuilder/TestPathBad.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/uribuilder/TestPathBad.java
new file mode 100644
index 0000000..4f8ed3c
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/api/rs/core/uribuilder/TestPathBad.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.api.rs.core.uribuilder;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.core.Response;
+
+public class TestPathBad {
+  @GET
+  public Response getPlain() {
+    return Response.ok().build();
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/AbstractMessageBodyRW.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/AbstractMessageBodyRW.java
new file mode 100644
index 0000000..a4c74d7
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/AbstractMessageBodyRW.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+import jakarta.ws.rs.Path;
+
+/**
+ * This class is a superclass used in MessageBodyWriters which need to check
+ * 
+ * @Path annotation value
+ */
+public abstract class AbstractMessageBodyRW {
+
+  public static String getPathValue(Annotation[] annotations) {
+    return getSpecifiedAnnotationValue(annotations, Path.class);
+  }
+
+  @SuppressWarnings("unchecked")
+  public static <T extends Annotation> T getSpecifiedAnnotation(
+      Annotation[] annotations, Class<T> clazz) {
+    T t = null;
+    for (Annotation a : annotations)
+      if (a.annotationType() == clazz)
+        t = (T) a;
+    return t != null ? t : null;
+  }
+
+  public static <T extends Annotation> String getSpecifiedAnnotationValue(
+      Annotation[] annotations, Class<T> clazz) {
+    T t = getSpecifiedAnnotation(annotations, clazz);
+    try {
+      Method m = clazz.getMethod("value");
+      return (String) m.invoke(t);
+    } catch (Exception e) {
+      return null;
+    }
+  }
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/JAXRSCommonClient.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/JAXRSCommonClient.java
new file mode 100644
index 0000000..f69dd67
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/JAXRSCommonClient.java
@@ -0,0 +1,1212 @@
+ /*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common;
+
+import java.io.*;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.nio.charset.StandardCharsets;
+
+
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.HttpState;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+import jakarta.ws.rs.tck.common.webclient.TestFailureException;
+import jakarta.ws.rs.tck.common.webclient.WebTestCase;
+import jakarta.ws.rs.tck.common.webclient.http.HttpRequest;
+import jakarta.ws.rs.tck.common.webclient.validation.CheckOneOfStatusesTokenizedValidator;
+import jakarta.ws.rs.tck.common.util.JaxrsUtil;
+import jakarta.ws.rs.tck.common.util.Data;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+
+/**
+ * 
+ * @author dianne jiao
+ * @author jan supol
+ */
+//public abstract class JAXRSCommonClient extends ServiceEETest {
+public abstract class JAXRSCommonClient {
+
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * TS Webserver host property
+   */
+  protected static final String SERVLETHOSTPROP = "webServerHost";
+
+  /**
+   * TS Webserver port property
+   */
+  protected static final String SERVLETPORTPROP = "webServerPort";
+
+  /**
+   * TS home property
+   */
+  protected static final String TSHOME = "ts_home";
+
+  /**
+   * Test properties
+   */
+  protected static final Hashtable<Property, String> TEST_PROPS = new Hashtable<Property, String>();
+
+  /**
+   * StatusCode property
+   */
+  protected static final String STATUS_CODE = "STATUS_CODE";
+
+  /**
+   * Request property
+   */
+  protected static final String REQUEST = "REQUEST";
+
+  /**
+   * Request headers property
+   */
+  protected static final String REQUEST_HEADERS = "REQUEST_HEADERS";
+
+  /**
+   * Goldenfile property
+   */
+  protected static final String GOLDENFILE = "goldenfile";
+
+  /**
+   * Search string property
+   */
+  protected static final String SEARCH_STRING = "SEARCH_STRING";
+
+  /**
+   * Search string case insensitive property
+   */
+  protected String TESTDIR = null;
+
+  /**
+   * Goldenfile directory
+   */
+  protected String GOLDENFILEDIR = "/src/web";
+
+  /**
+   * Default request method
+   */
+  protected static final String GET = "GET ";
+
+  /**
+   * HTTP 1.0
+   */
+  protected static final String HTTP10 = " HTTP/1.0";
+
+  /**
+   * HTTP 1.1
+   */
+  protected static final String HTTP11 = " HTTP/1.1";
+
+  /**
+   * Forward slash
+   */
+  protected static final String SL = "/";
+
+  /**
+   * Goldenfile suffix
+   */
+  protected static final String GF_SUFFIX = ".gf";
+
+  /**
+   * JSP suffix
+   */
+  /**
+   * Current test name
+   */
+  protected String _testName = null;
+
+  /**
+   * location of _tsHome
+   */
+  protected String _tsHome = null;
+
+  /**
+   * Context root of target tests
+   */
+  public String _contextRoot = null;
+
+  /**
+   * General file/request URI for both gfiles and tests
+   */
+  protected String _generalURI = null;
+
+  /**
+   * Target webserver hostname
+   */
+  protected String _hostname = null;
+
+  /**
+   * Target webserver port
+   */
+  protected int _port = 0;
+
+  /**
+   * HttpState that may be used for multiple invocations requiring state.
+   */
+  protected HttpState _state = null;
+
+  /**
+   * Test case.
+   */
+  protected WebTestCase _testCase = null;
+
+  /**
+   * Use saved state.
+   */
+  protected boolean _useSavedState = false;
+
+  /**
+   * Save state.
+   */
+  protected boolean _saveState = false;
+
+  protected boolean _redirect = false;
+
+  public static final String newline = System.getProperty("line.separator");
+
+  public static final String servletAdaptor = System.getProperty("servlet_adaptor", "org.glassfish.jersey.servlet.ServletContainer");
+
+  public static final String indent = "    ";
+
+  /**
+   * List of possible requests
+   */
+  protected enum Request {
+    GET, PUT, POST, HEAD, OPTIONS, DELETE, TRACE
+  }
+
+  /**
+   * the list of properties to be put into a property table
+   */
+  protected enum Property {
+    APITEST, BASIC_AUTH_PASSWD, BASIC_AUTH_REALM, BASIC_AUTH_USER, //
+    CONTENT, DONOTUSEServletName, EXPECT_RESPONSE_BODY, EXPECTED_HEADERS, //
+    FOLLOW_REDIRECT, GOLDENFILE, IGNORE_BODY, IGNORE_STATUS_CODE, //
+    REASON_PHRASE, REQUEST, REQUEST_HEADERS, RESPONSE_MATCH, SAVE_STATE, //
+    SEARCH_STRING, SEARCH_STRING_IGNORE_CASE, STANDARD, STATUS_CODE, //
+    STRATEGY, TEST_NAME, UNEXPECTED_HEADERS, UNEXPECTED_RESPONSE_MATCH, //
+    UNORDERED_SEARCH_STRING, USE_SAVED_STATE;
+  }
+
+  /*
+   * public methods
+   * ========================================================================
+   */
+  /**
+   * <code>setTestDir</code> sets the current test directory.
+   * 
+   * @param testDir
+   *          a <code>String</code> value
+   */
+  public void setTestDir(String testDir) {
+    TestUtil.logTrace("[JAXRSCommonClient] setTestDir");
+    TESTDIR = testDir;
+  }
+
+  public void setContextRoot(String root) {
+    TestUtil.logTrace("[JAXRSCommonClient] Contextroot set at " + root);
+    _contextRoot = root;
+  }
+
+  public String getContextRoot() {
+    TestUtil.logTrace("[JAXRSCommonClient]getContextRoot");
+    return _contextRoot;
+  }
+
+  /**
+   * <code>setup</code> is by the test harness to initialize the tests.
+   * 
+   * @param args
+   *          a <code>String[]</code> value
+   * @param p
+   *          a <code>Properties</code> value
+   * @exception Fault
+   *              if an error occurs
+   */
+  //public void setup(String[] args, Properties p)   {
+  public void setup()   {
+    TestUtil.logTrace("setup method JAXRSCommonClient");
+
+    String hostname = System.getProperty(SERVLETHOSTPROP);
+    String portnum = System.getProperty(SERVLETPORTPROP);
+    //String tshome = p.getProperty(TSHOME);
+
+    assertTrue(!isNullOrEmpty(hostname),
+        "[JAXRSCommonClient] 'webServerHost' was not set.");
+    _hostname = hostname.trim();
+    assertTrue(!isNullOrEmpty(portnum),
+        "[JAXRSCommonClient] 'webServerPort' was not set.");
+    _port = Integer.parseInt(portnum.trim());
+
+    //assertTrue(!isNullOrEmpty(tshome),
+    //    "[JAXRSCommonClient] 'tshome' was not set in the build.properties.");
+    //_tsHome = tshome.trim();
+
+    TestUtil.logMsg("[JAXRSCommonClient] Test setup OK");
+  }
+
+  /**
+   * <code>cleanup</code> is called by the test harness to cleanup after text
+   * execution
+   * 
+   * @exception Fault
+   *              if an error occurs
+   */
+  public void cleanup() throws Fault  {
+    TestUtil.logMsg("[JAXRSCommonClient] Test cleanup OK");
+  }
+
+  /*
+   * protected methods
+   * ========================================================================
+   */
+  /**
+   * <PRE>
+   * Invokes a test based on the properties
+   * stored in TEST_PROPS.  Once the test has completed,
+   * the properties in TEST_PROPS will be cleared.
+   * </PRE>
+   * 
+   * @throws Fault
+   *           If an error occurs during the test run
+   */
+  protected void invoke() throws Fault {
+    TestUtil.logTrace("[JAXRSCommonClient] invoke");
+    try {
+      _testCase = new WebTestCase();
+      setTestProperties(_testCase);
+      TestUtil.logTrace("[JAXRSCommonClient] EXECUTING");
+      if (_useSavedState && _state != null) {
+        _testCase.getRequest().setState(_state);
+      }
+      if (_redirect != false) {
+        TestUtil.logTrace("##########Call setFollowRedirects");
+        _testCase.getRequest().setFollowRedirects(_redirect);
+      }
+      _testCase.execute();
+      if (_saveState) {
+        _state = _testCase.getResponse().getState();
+      }
+    } catch (TestFailureException tfe) {
+      Throwable t = tfe.getRootCause();
+      if (t != null) {
+        TestUtil.logErr("Root cause of Failure: " + t.getMessage(), t);
+        if (t instanceof RuntimeException) {
+          throw (RuntimeException) t;
+        } else if (t instanceof Error) {
+          throw (Error) t;
+        } else {
+          throw new RuntimeException(t);
+        }
+      }
+      throw new Fault("[JAXRSCommonClient] " + _testName
+          + " failed!  Check output for cause of failure.", tfe);
+    } finally {
+      _useSavedState = false;
+      _saveState = false;
+      _redirect = false;
+      clearTestProperties();
+    }
+  }
+
+  /**
+   * <PRE>
+   * Sets the appropriate test properties based
+   * on the values stored in TEST_PROPS
+   * </PRE>
+   */
+  protected void setTestProperties(WebTestCase testCase) {
+    TestUtil.logTrace("[JAXRSCommonClient] setTestProperties");
+
+    setStandardProperties(TEST_PROPS.get(Property.STANDARD), testCase);
+    setApiTestProperties(TEST_PROPS.get(Property.APITEST), testCase);
+
+    if (TEST_PROPS.get(Property.STATUS_CODE) == null)
+      setProperty(Property.STATUS_CODE, getStatusCode(Response.Status.OK));
+
+    HttpRequest req = testCase.getRequest();
+
+    // Check for a request object. If doesn't exist, then
+    // check for a REQUEST property and create the request object.
+    if (req == null)
+      req = setWebTestCaseRequest(testCase, null);
+    setWebTestCaseProperties(testCase, req);
+  }
+
+  protected HttpRequest setWebTestCaseRequest(WebTestCase testCase,
+      HttpRequest req) {
+    String request = TEST_PROPS.get(Property.REQUEST);
+    boolean isRequest = false;
+    for (Request r : Request.values())
+      if (request.startsWith(r.name()))
+        isRequest = true;
+    if (request.endsWith(HTTP10) || request.endsWith(HTTP11))
+      isRequest = true;
+    if (isRequest) {
+      // user has overridden default request behavior
+      req = createHttpRequest(request, _hostname, _port);
+      testCase.setRequest(req);
+    } else {
+      req = createHttpRequest(getTSRequest(request), _hostname, _port);
+      testCase.setRequest(req);
+    }
+    return req;
+  }
+
+  protected void setWebTestCaseProperties(WebTestCase testCase,
+      HttpRequest req) {
+    Property key = null;
+    String value = null;
+    // process the remainder of the properties
+    for (Enumeration<Property> e = TEST_PROPS.keys(); e.hasMoreElements();) {
+      key = e.nextElement();
+      value = TEST_PROPS.get(key);
+      switch (key) {
+      case APITEST:
+        break;
+      case BASIC_AUTH_PASSWD:
+      case BASIC_AUTH_REALM:
+      case BASIC_AUTH_USER:
+        String user = TEST_PROPS.get(Property.BASIC_AUTH_USER);
+        String password = TEST_PROPS.get(Property.BASIC_AUTH_PASSWD);
+        String realm = TEST_PROPS.get(Property.BASIC_AUTH_REALM);
+        req.setAuthenticationCredentials(user, password,
+            HttpRequest.BASIC_AUTHENTICATION, realm);
+        break;
+      case CONTENT:
+        req.setContent(value);
+        break;
+      case DONOTUSEServletName:
+        break;
+      case EXPECT_RESPONSE_BODY:
+        // FIXME
+        // setExpectResponseBody(false);
+        break;
+      case EXPECTED_HEADERS:
+        testCase.addExpectedHeader(value);
+        break;
+      case FOLLOW_REDIRECT:
+        TestUtil.logTrace("##########Found redirect Property");
+        _redirect = true;
+        break;
+      case GOLDENFILE:
+        StringBuffer sb = new StringBuffer(50);
+        sb.append(_tsHome).append(GOLDENFILEDIR);
+        sb.append(_generalURI).append(SL);
+        sb.append(value);
+        testCase.setGoldenFilePath(sb.toString());
+        break;
+      case IGNORE_BODY:
+        // FIXME
+        // setIgnoreResponseBody(true);
+        testCase.setGoldenFilePath(null);
+        break;
+      case IGNORE_STATUS_CODE:
+        testCase.setExpectedStatusCode("-1");
+        break;
+      case REASON_PHRASE:
+        testCase.setExpectedReasonPhrase(value);
+        break;
+      case REQUEST:
+        break;
+      case REQUEST_HEADERS:
+        req.addRequestHeader(value);
+        break;
+      case RESPONSE_MATCH:
+        // setResponseMatch(TEST_PROPS.getProperty(key));
+        break;
+      case SAVE_STATE:
+        _saveState = true;
+        break;
+      case SEARCH_STRING:
+        testCase.setResponseSearchString(value);
+        break;
+      case SEARCH_STRING_IGNORE_CASE:
+        testCase.setResponseSearchStringIgnoreCase(value);
+        break;
+      case STANDARD:
+        break;
+      case STATUS_CODE:
+        if (value.contains("|"))
+          testCase.setStrategy(
+              CheckOneOfStatusesTokenizedValidator.class.getName());
+        testCase.setExpectedStatusCode(value);
+        break;
+      case STRATEGY:
+        testCase.setStrategy(value);
+        break;
+      case TEST_NAME:
+        // testName = TEST_PROPS.getProperty(key);
+        break;
+      case UNEXPECTED_HEADERS:
+        testCase.addUnexpectedHeader(value);
+        break;
+      case UNEXPECTED_RESPONSE_MATCH:
+        testCase.setUnexpectedResponseSearchString(value);
+        break;
+      case UNORDERED_SEARCH_STRING:
+        testCase.setUnorderedSearchString(value);
+        break;
+      case USE_SAVED_STATE:
+        _useSavedState = true;
+        break;
+      }
+    }
+  }
+
+  /**
+   * Create request <type> /<contextroot>/<path> HTTP/1.1. ContextRoot is
+   * defined in every client.
+   * 
+   * @param type
+   *          PUT, GET, POST, ...
+   * @param path
+   *          path defined in a servlet
+   * @return String representing HTTP request
+   */
+  protected String buildRequest(String type, String... path) {
+    StringBuilder sb = new StringBuilder();
+    sb.append(type).append(" ").append(_contextRoot).append(SL);
+    for (String segment : path)
+      sb.append(segment);
+    sb.append(HTTP11);
+    return sb.toString();
+  }
+
+  protected String buildRequest(Request type, String... path) {
+    return buildRequest(type.name(), path);
+  }
+
+  protected String buildRequest10(Request type, String... path) {
+    return buildRequest(type, path).replace(HTTP11, HTTP10);
+  }
+
+  /**
+   * Create counterpart to @Produces
+   * 
+   * @param type
+   * @return Accept:{@code type}.{@link #toString()}
+   */
+  protected static String buildAccept(MediaType type) {
+    return buildHeaderMediaType("Accept", type);
+  }
+
+  /**
+   * Create counterpart to @Consumes
+   * 
+   * @param type
+   * @return
+   */
+  protected static String buildContentType(MediaType type) {
+    return buildHeaderMediaType("Content-Type", type);
+  }
+
+  protected static String buildHeaderMediaType(String header, MediaType type) {
+    StringBuilder sb = new StringBuilder();
+    sb.append(header).append(":").append(type.getType()).append(SL);
+    sb.append(type.getSubtype());
+    return sb.toString();
+  }
+
+  public static String editWebXmlString(InputStream inStream) throws IOException{
+    String line;
+    String webXmlTemplate = "";
+    try (BufferedReader bufReader = new BufferedReader(new InputStreamReader(inStream, StandardCharsets.UTF_8))) {
+      while ((line = bufReader.readLine()) != null) {
+        webXmlTemplate = webXmlTemplate + line + System.lineSeparator();
+      }
+    }
+    
+    String webXml = webXmlTemplate.replaceAll("servlet_adaptor", servletAdaptor);
+    return webXml;
+  }
+
+  /**
+   * @return http response body as string
+   * @throws Fault
+   *           when an error occur
+   */
+  protected String getResponseBody() throws Fault  {
+    try {
+      jakarta.ws.rs.tck.common.webclient.http.HttpResponse response;
+      response = _testCase.getResponse();
+      boolean isNull = response.getResponseBodyAsRawStream() == null;
+      return isNull ? null : response.getResponseBodyAsString();
+    } catch (IOException e) {
+        throw new Fault(e);
+    }
+  }
+
+  /**
+   * @return http response body as string
+   * @throws Fault
+   *           when an error occur
+   */
+  protected String[] getResponseHeaders() throws Fault  {
+    Header[] headerEntities = _testCase.getResponse().getResponseHeaders();
+    String[] headers = new String[headerEntities.length];
+    for (int i = 0; i != headerEntities.length; i++)
+      headers[i] = headerEntities[i].toString();
+    return headers;
+  }
+
+  /**
+   * @param s
+   *          the header to search
+   * @throws Fault
+   *           when header not found
+   */
+  protected void assertResponseHeadersContain(String s) throws Fault  {
+    boolean found = false;
+    for (String header : getResponseHeaders())
+      if (header.contains(s)) {
+        found = true;
+        break;
+      }
+    assertTrue(found, "Response headers do not contain"+ s);
+  }
+
+  /**
+   * @param s
+   *          the entity to search
+   * @throws Fault
+   *           when entity not found
+   */
+  protected void assertResponseBodyContain(String s)  throws Fault {
+    boolean found = getResponseBody().contains(s);
+    assertTrue(found, "Response body does not contain"+ s);
+  }
+
+  /**
+   * get HttpResponse#statusCode
+   * 
+   * @return JAXRS Response.Status equivalent of HttpResponse#statusCode
+   */
+  protected Response.Status getResponseStatusCode() {
+    String status = _testCase.getResponse().getStatusCode();
+    return Response.Status.fromStatusCode(Integer.parseInt(status));
+  }
+
+  /**
+   * Set TEST_PROPS property value. If it already exists, the value is appended
+   */
+  protected void setProperty(String key, String value) {
+    Property property = Property.valueOf(key);
+    setProperty(property, value);
+  }
+
+  /*
+   * @since 2.0.1
+   */
+  protected void setProperty(Property key, String... value) {
+    setProperty(key, objectsToString("", (Object[]) value));
+  }
+
+  protected void setProperty(Property key, String value) {
+    String oldValue = TEST_PROPS.get(key);
+    if (oldValue == null) {
+      TEST_PROPS.put(key, value);
+    } else {
+      int len = value.length() + oldValue.length() + 1;
+      StringBuilder combinedValue = new StringBuilder(len);
+      combinedValue.append(oldValue).append("|").append(value);
+      TEST_PROPS.put(key, combinedValue.toString());
+    }
+  }
+
+  protected void clearProperty(Property key) {
+    TEST_PROPS.remove(key);
+  }
+
+  /**
+   * This pattern is used in all subclasses
+   */
+  //protected Status run(String[] args) {
+  //  Status s;
+  //  s = run(args, new PrintWriter(System.out), new PrintWriter(System.err));
+  //  s.exit();
+  //  return s;
+  //}
+
+  /**
+   * Asserts that a condition is true.
+   * 
+   * @param conditionTrue
+   *          tested condition
+   * @param message
+   *          a space separated message[i].toString() compilation for
+   *          i=<0,message.length)
+   * @ 
+   *           when conditionTrue is not met with message provided
+   */
+  /*public static void //
+      assertFault(boolean conditionTrue, Object... message)   {
+    assertTrue(conditionTrue, message);
+  }*/
+
+  /**
+   * Asserts that a condition is true.
+   * 
+   * @param condition
+   *          tested condition
+   * @param message
+   *          a space separated message[i].toString() compilation for
+   *          i=<0,message.length)
+   * @ 
+   *           when conditionTrue is not met with message provided
+   */
+  //public static void //
+  //    assertTrue(boolean condition, Object... message)   {
+  //  if (!condition)
+  //    fail(message);
+  //}
+
+  /**
+   * Asserts that a condition is false.
+   * 
+   * @param condition
+   *          tested condition
+   * @param message
+   *          a space separated message[i].toString() compilation for
+   *          i=<0,message.length)
+   * @ 
+   *           when condition is not false with message provided
+   */
+  /*public static void //
+      assertFalse(boolean condition, Object... message)   {
+    assertTrue(!condition, message);
+  }*/
+
+  /**
+   * Asserts that two objects are equal. When instances of Comparable, such as
+   * String, compareTo is used.
+   * 
+   * @param first
+   *          first object
+   * @param second
+   *          second object
+   * @param message
+   *          a space separated message[i].toString() compilation for
+   *          i=<0,message.length)
+   * @ 
+   *           when objects are not equal with message provided
+   */
+  @SuppressWarnings("unchecked")
+  public static <T> void //
+      assertEquals(T first, T second, Object... message)   {
+    if (first == null && second == null)
+      return;
+    assertFalse(first == null && second != null, message.toString());
+    assertFalse(first != null && second == null, message.toString());
+    if (first instanceof Comparable)
+      assertTrue(((Comparable<T>) first).compareTo(second) == 0, message.toString());
+    else
+      assertTrue(first.equals(second), message.toString());
+  }
+
+  public static <T> void //
+      assertEqualsInt(int first, int second, Object... message)   {
+    assertTrue(first == second, message.toString());
+  }
+
+  public static <T> void //
+      assertEqualsLong(long first, long second, Object... message)
+            {
+    assertTrue(first == second, message.toString());
+  }
+
+  public static <T> void //
+      assertEqualsBool(boolean first, boolean second, Object... message)
+            {
+    assertTrue(first == second, message.toString());
+  }
+
+  /**
+   * Asserts that an object is null.
+   * 
+   * @param object
+   *          Assert that object is not null
+   * @param message
+   *          a space separated message[i].toString() compilation for
+   *          i=<0,message.length)
+   */
+  public static void //
+      assertNull(Object object, Object... message) {
+    assertTrue(object == null, message.toString());
+  }
+
+  /**
+   * Asserts that an object is not null.
+   * 
+   * @param object
+   *          Assert that object is not null
+   * @param message
+   *          a space separated message[i].toString() compilation for
+   *          i=<0,message.length)
+   */
+  public static void //
+      assertNotNull(Object object, Object... message) {
+    assertTrue(object != null, message.toString());
+  }
+
+  /**
+   * Throws Fault with space separated objects[1],object[2],...,object[n]
+   * message
+   * 
+   * @param objects
+   *          objects whose toString() results will be added to Fault message
+   * @throws Fault
+   *           fault with space separated objects.toString values
+   */
+  public static void fault(Object... objects) throws Fault  {
+    throw new Fault(objectsToString(objects));
+  }
+
+  /**
+   * Assert that given substring is a substring of given string
+   * 
+   * @param string
+   *          the string to search substring in
+   * @param substring
+   *          the substring to be searched in a given string
+   * @param message
+   *          space separated message values to be thrown
+   * @ 
+   *           throws
+   */
+  public static void assertContains(String string, String substring,
+      Object... message)   {
+    assertTrue(string.contains(substring), message.toString());
+  }
+
+  /**
+   * Assert that given substring is a substring of given string, case
+   * insensitive
+   * 
+   * @param string
+   *          the string to search substring in
+   * @param substring
+   *          the substring to be searched in a given string
+   * @param message
+   *          space separated message values to be thrown
+   * @ 
+   */
+  public static void assertContainsIgnoreCase(String string, String substring,
+      Object... message)   {
+    assertTrue(string.toLowerCase().contains(substring.toLowerCase()), message.toString());
+  }
+
+  /**
+   * Assert that given subtext.toString() subject is a substring of given text
+   * 
+   * @param text
+   *          the text.toString() object to search subtext.toString() in
+   * @param subtext
+   *          the subtext.toString() to be searched in a given text.toString()
+   * @param message
+   *          space separated message values to be thrown
+   * @ 
+   */
+  public static <T> void assertContains(T text, T subtext, Object... message)
+        {
+    assertContains(text.toString(), subtext.toString(), message.toString());
+  }
+
+  /**
+   * Assert that given subtext.toString() subject is a substring of given text,
+   * case insensitive
+   * 
+   * @param text
+   *          the text.toString() object to search subtext.toString() in
+   * @param subtext
+   *          the subtext.toString() to be searched in a given text.toString()
+   * @param message
+   *          space separated message values to be thrown
+   * @ 
+   */
+  public static <T> void assertContainsIgnoreCase(T text, T subtext,
+      Object... message)   {
+    assertContainsIgnoreCase(text.toString(), subtext.toString(), message.toString());
+  }
+
+  /**
+   * Searches an encapsulated exception cause in parent exception
+   */
+  protected static <T extends Throwable> T assertCause(Throwable parent,
+      Class<T> wrapped, Object... msg)   {
+    T t = hasCause(parent, wrapped);
+    assertNotNull(t, msg);
+    return t;
+  }
+
+  @SuppressWarnings("unchecked")
+  private static <T extends Throwable> T //
+      hasCause(Throwable parent, Class<? extends Throwable> cause) {
+    while (parent != null) {
+      if (cause.isInstance(parent))
+        return (T) parent;
+      parent = parent.getCause();
+    }
+    return null;
+  }
+
+  public static String getStatusCode(Response.Status status) {
+    return String.valueOf(status.getStatusCode());
+  }
+
+  public static void logMsg(Object... msg) {
+    TestUtil.logMsg(objectsToString(msg));
+  }
+
+  public static void logTrace(Object... msg) {
+    TestUtil.logTrace(objectsToString(msg));
+  }
+
+  /**
+   * Use rather this method than
+   * {@link JaxrsUtil#iterableToString(String, Iterable)} since not all wars
+   * (for servlet vehicle, api) do contain JaxrsUtil
+   * 
+   * @param objects
+   * @return objects in a single string , each object separated by " "
+   */
+  protected static String objectsToString(Object... objects) {
+    return objectsToString(" ", objects);
+  }
+
+  /**
+   * @since 2.0.1
+   */
+  protected static String objectsToString(String delimiter, Object... objects) {
+    StringBuilder sb = new StringBuilder();
+    for (Object o : objects)
+      sb.append(o).append(delimiter);
+    return sb.toString().trim();
+  }
+
+  /*
+   * private methods
+   * ========================================================================
+   */
+  private String getTSRequest(String request) {
+    TestUtil.logTrace("[JAXRSCommonClient] getTSRequest");
+    StringBuffer finReq = new StringBuffer(50);
+    finReq.append(GET).append(_contextRoot).append(SL).append(_generalURI);
+    finReq.append(SL).append(request).append(HTTP11);
+    return finReq.toString();
+  }
+
+  /**
+   * Clears the contents of TEST_PROPS
+   */
+  protected void clearTestProperties() {
+    TEST_PROPS.clear();
+  }
+
+  protected boolean isNullOrEmpty(String val) {
+    return val == null || val.trim().equals("");
+  }
+
+  private InetAddress[] _addrs = null;
+
+  protected String _servlet = null;
+
+  /**
+   * Sets the request, testname, and a search string for test passed. A search
+   * is also added for test failure. If found, the test will fail.
+   * 
+   * @param testValue
+   *          - a logical test identifier
+   * @param testCase
+   *          - the current test case
+   */
+  private void setApiTestProperties(String testValue, WebTestCase testCase) {
+    TestUtil.logTrace("[JAXRSCommonClient] setApiTestProperties");
+
+    if (testValue == null) {
+      return;
+    }
+
+    // An API test consists of a request with a request parameter of
+    // testname, a search string of Test PASSED, and a logical test name.
+
+    // set the testname
+    _testName = testValue;
+
+    // set the request
+    StringBuffer sb = new StringBuffer(50);
+    if ((_servlet != null)
+        && (TEST_PROPS.get(Property.DONOTUSEServletName) == null)) {
+      sb.append(GET).append(_contextRoot).append(SL);
+      sb.append(_servlet).append("?testname=").append(testValue);
+      sb.append(HTTP11);
+    } else {
+      sb.append(GET).append(_contextRoot).append(SL);
+      sb.append(testValue).append(HTTP10);
+    }
+    System.out.println("REQUEST LINE: " + sb.toString());
+
+    HttpRequest req = createHttpRequest(sb.toString(), _hostname, _port);
+    testCase.setRequest(req);
+
+    String value = TEST_PROPS.get(Property.SEARCH_STRING);
+    if (isNullOrEmpty(value)) {
+      testCase.setResponseSearchString(Data.PASSED);
+      testCase.setUnexpectedResponseSearchString(Data.FAILED);
+    }
+  }
+
+  protected HttpRequest createHttpRequest(String requestLine, String host,
+      int port) {
+    return new HttpRequest(requestLine, host, port);
+  }
+
+  /**
+   * Consists of a test name, a request, and a goldenfile.
+   * 
+   * @param testValue
+   *          - a logical test identifier
+   * @param testCase
+   *          - the current test case
+   */
+  private void setStandardProperties(String testValue, WebTestCase testCase) {
+    TestUtil.logTrace("[JAXRSCommonClient] setStandardProperties");
+
+    if (testValue == null) {
+      return;
+    }
+    // A standard test sets consists of a testname
+    // a request, and a goldenfile. The URI is not used
+    // in this case since the JSP's are assumed to be located
+    // at the top of the contextRoot
+    String req;
+
+    // set the testname
+    _testName = testValue;
+
+    if (_servlet != null) {
+      req = buildRequest(Request.GET, _servlet, "?testname=", testValue);
+    } else {
+      req = buildRequest10(Request.GET, testValue);
+    }
+    System.out.println("REQUEST LINE: " + req);
+    System.out.println("_hostname=" + _hostname);
+    HttpRequest httpReq = createHttpRequest(req, _hostname, _port);
+    testCase.setRequest(httpReq);
+
+    // set the goldenfile
+    StringBuffer sb = new StringBuffer(50);
+    sb.append(_tsHome).append(GOLDENFILEDIR);
+    sb.append(_generalURI).append(SL);
+    sb.append(testValue).append(GF_SUFFIX);
+    testCase.setGoldenFilePath(sb.toString());
+  }
+
+  /**
+   * Sets the name of the servlet to use when building a request for a single
+   * servlet API test.
+   * 
+   * @param servlet
+   *          - the name of the servlet
+   */
+  protected void setServletName(String servlet) {
+    TestUtil.logTrace("[JAXRSCommonClient] setServletName");
+    _servlet = servlet;
+  }
+
+  protected String getServletName() {
+    return _servlet;
+  }
+
+  protected String getLocalInterfaceInfo(boolean returnAddresses) {
+    String result = null;
+    initInetAddress();
+    if (_addrs.length != 0) {
+      StringBuffer sb = new StringBuffer(32);
+      if (!returnAddresses) {
+        // localhost might not show up if aliased
+        sb.append("localhost,");
+      } else {
+        // add 127.0.0.1
+        sb.append("127.0.0.1,");
+      }
+
+      for (int i = 0; i < _addrs.length; i++) {
+        if (returnAddresses) {
+          String ip = _addrs[i].getHostAddress();
+          if (!ip.equals("127.0.0.1")) {
+            if (ip.contains("%")) {
+              int scope_id = ip.indexOf("%");
+              ip = ip.substring(0, scope_id);
+            }
+            sb.append(ip);
+          }
+        } else {
+          String host = _addrs[i].getCanonicalHostName();
+          if (!host.equals("localhost")) {
+            sb.append(host);
+          }
+        }
+        if (i + 1 != _addrs.length) {
+          sb.append(",");
+        }
+      }
+      result = sb.toString();
+      TestUtil.logTrace("[AbstractUrlClient] Interface info: " + result);
+    }
+    return result;
+  }
+
+  private void initInetAddress() {
+    if (_addrs == null) {
+      try {
+        _addrs = InetAddress
+            .getAllByName(InetAddress.getLocalHost().getCanonicalHostName());
+      } catch (UnknownHostException uhe) {
+        TestUtil.logMsg(
+            "[AbstractUrlClient][WARNING] Unable to obtain local host information.");
+      }
+    }
+  }
+
+  protected String getAbsoluteUrl() {
+    return getAbsoluteUrl(null);
+  }
+
+  protected String getAbsoluteUrl(String method) {
+    StringBuilder sb = new StringBuilder();
+    sb.append("http://").append(_hostname).append(":").append(_port)
+        .append(getContextRoot());
+    if (method != null)
+      sb.append("/").append(method);
+    return sb.toString();
+  }
+
+  /**
+   * This exception must be thrown to signify a
+   * test failure. Overrides 3 printStackTrace methods to preserve the original
+   * stack trace.
+   *
+   * @author Kyle Grucci
+   */
+
+  public static class Fault extends Exception {
+    private static final long serialVersionUID = -1574745208867827913L;
+
+    public Throwable t;
+
+    /**
+     * creates a Fault with a message
+     */
+    public Fault(String msg) {
+      super(msg);
+      TestUtil.logErr(msg);
+    }
+
+    /**
+     * creates a Fault with a message.
+     *
+     * @param msg
+     *          the message
+     * @param t
+     *          prints this exception's stacktrace
+     */
+    public Fault(String msg, Throwable t) {
+      super(msg);
+      this.t = t;
+      TestUtil.logErr(msg, t);
+    }
+
+    /**
+     * creates a Fault with a Throwable.
+     *
+     * @param t
+     *          the Throwable
+     */
+    public Fault(Throwable t) {
+      super(t);
+      this.t = t;
+    }
+
+    /**
+     * Prints this Throwable and its backtrace to the standard error stream.
+     *
+     */
+    public void printStackTrace() {
+      if (this.t != null) {
+        this.t.printStackTrace();
+      } else {
+        super.printStackTrace();
+      }
+    }
+
+    /**
+     * Prints this throwable and its backtrace to the specified print stream.
+     *
+     * @param s
+     *          <code>PrintStream</code> to use for output
+     */
+    public void printStackTrace(PrintStream s) {
+      if (this.t != null) {
+        this.t.printStackTrace(s);
+      } else {
+        super.printStackTrace(s);
+      }
+    }
+
+    /**
+     * Prints this throwable and its backtrace to the specified print writer.
+     *
+     * @param s
+     *          <code>PrintWriter</code> to use for output
+     */
+    public void printStackTrace(PrintWriter s) {
+      if (this.t != null) {
+        this.t.printStackTrace(s);
+      } else {
+        super.printStackTrace(s);
+      }
+    }
+
+    @Override
+    public Throwable getCause() {
+      return t;
+    }
+
+    @Override
+    public synchronized Throwable initCause(Throwable cause) {
+      if (t != null)
+        throw new IllegalStateException("Can't overwrite cause");
+      if (!Exception.class.isInstance(cause))
+        throw new IllegalArgumentException("Cause not permitted");
+      this.t = (Exception) cause;
+      return this;
+    }
+  }
+
+}
\ No newline at end of file
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/Version.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/Version.java
new file mode 100644
index 0000000..269b5de
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/Version.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common;
+
+/**
+ * There were references to the following versions of TCK:
+ * <p>
+ * 1.0 - The tests that used jakarta.ws.rs.tck.common.JAXRSCommonClient as
+ * a superclass.
+ * </p>
+ * <p>
+ * 1.1 - The tests that used jakarta.ws.rs.tck.common.JAXRSCommonClient as
+ * a superclass.
+ * </p>
+ * <p>
+ * 2.0 - The tests that used mainly
+ * jakarta.ws.rs.tck.common.client.JaxrsCommonClient, sometimes
+ * jakarta.ws.rs.tck.common.JAXRSCommonClient as a superclass.
+ * </p>
+ * <p>
+ * 2.0.1 - The code that has been created after JAXRS 2.0 TCK bundle has been
+ * built
+ * </p>
+ * <p>
+ * 2.1 - The code that has been created for JAXRS 2.1 TCK
+ * 
+ * @since 2.0.1
+ */
+public interface Version {
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/ApacheRequestAdapter.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/ApacheRequestAdapter.java
new file mode 100644
index 0000000..b6e0004
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/ApacheRequestAdapter.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common.client;
+
+import jakarta.ws.rs.tck.common.webclient.http.HttpRequest;
+
+public class ApacheRequestAdapter extends HttpRequest {
+
+  public ApacheRequestAdapter(String requestLine, String host, int port) {
+    super(requestLine, host, port);
+  }
+
+  /**
+   * <code>getRequestPath</code> returns the request path for this particular
+   * request.
+   *
+   * @return String request path
+   */
+  public String getRequestPath() {
+    return super.getRequestPath();
+  }
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/ApacheResponseAdapter.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/ApacheResponseAdapter.java
new file mode 100644
index 0000000..16eedcf
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/ApacheResponseAdapter.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common.client;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.httpclient.Header;
+import jakarta.ws.rs.tck.common.webclient.http.HttpResponse;
+import jakarta.ws.rs.core.MultivaluedMap;
+
+public class ApacheResponseAdapter extends HttpResponse {
+
+  public ApacheResponseAdapter(jakarta.ws.rs.core.Response response, String host,
+      int port) {
+    super(host, port, port == 443, null, null);
+    this.response = response;
+    this.caser = TextCaser.NONE;
+  }
+
+  public ApacheResponseAdapter(jakarta.ws.rs.core.Response response, String host,
+      int port, TextCaser caser) {
+    this(response, host, port);
+    this.caser = caser;
+  }
+
+  private jakarta.ws.rs.core.Response response;
+
+  private String entity = null;
+
+  private TextCaser caser = null;
+
+  /**
+   * Returns the HTTP status code returned by the server
+   * 
+   * @return HTTP status code
+   */
+  public String getStatusCode() {
+    return Integer.toString(response.getStatus());
+  }
+
+  @Override
+  public String getResponseBodyAsString() throws IOException {
+    if (entity == null)
+      entity = response.readEntity(String.class);
+    return entity == null ? "" : caser.getCasedText(entity);
+  }
+
+  @Override
+  public String getResponseBodyAsRawString() throws IOException {
+    return getResponseBodyAsString();
+  }
+
+  @Override
+  public String getReasonPhrase() {
+    return response.toString();// getReasonPhrase();
+  }
+
+  @Override
+  public Header[] getResponseHeaders() {
+    List<Header> headers = new LinkedList<Header>();
+    MultivaluedMap<String, Object> mHeaders = response.getMetadata();
+    String[] sHeaders = JaxrsCommonClient.getMetadata(mHeaders);
+    for (String header : sHeaders) {
+      String[] split = header.split(":", 2);
+      headers.add(new Header(split[0], split[1]));
+    }
+    return headers.toArray(new Header[headers.size()]);
+  }
+
+  @Override
+  public Header getResponseHeader(String headerName) {
+    for (Header header : getResponseHeaders())
+      if (header.getName().equals(headerName))
+        return header;
+    return null;
+  }
+
+  @Override
+  public String getResponseEncoding() {
+    String encoding = null;
+    Header header = getResponseHeader("Content-Type");
+    if (header != null) {
+      String headerVal = header.getValue();
+      int idx = headerVal.indexOf(";charset=");
+      if (idx > -1) {
+        // content encoding included in response
+        encoding = headerVal.substring(idx + 9);
+      }
+    }
+    return encoding;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/JaxrsCommonClient.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/JaxrsCommonClient.java
new file mode 100644
index 0000000..b16bda8
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/JaxrsCommonClient.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common.client;
+
+import java.util.Enumeration;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import jakarta.ws.rs.tck.lib.util.BASE64Encoder;
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+import jakarta.ws.rs.tck.common.webclient.TestFailureException;
+import jakarta.ws.rs.tck.common.webclient.validation.CheckOneOfStatusesTokenizedValidator;
+import jakarta.ws.rs.tck.common.JAXRSCommonClient;
+import jakarta.ws.rs.tck.common.client.JaxrsWebTestCase.Execution;
+
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.Response.Status;
+
+public class JaxrsCommonClient extends JAXRSCommonClient {
+
+  private static final long serialVersionUID = 1L;
+
+  protected transient JaxrsWebTestCase testCase;
+
+  protected boolean isTestCaseAfterInvocation;
+
+  // list of clients to be closed automatically at cleanup
+  protected List<Client> clients = new LinkedList<Client>();
+
+  /**
+   * <PRE>
+   * Sets the appropriate test properties based
+   * on the values stored in TEST_PROPS
+   * </PRE>
+   */
+  protected void setTestProperties(JaxrsWebTestCase testCase) {
+    TestUtil.logTrace("[JAXRSCommonClient] setTestProperties");
+
+    if (TEST_PROPS.get(Property.STATUS_CODE) == null)
+      setProperty(Property.STATUS_CODE, getStatusCode(Response.Status.OK));
+    setWebTestCaseProperties(testCase);
+  }
+
+  protected void setWebTestCaseProperties(JaxrsWebTestCase testCase) {
+    Property key = null;
+    String value = null;
+    // process the remainder of the properties
+    for (Enumeration<Property> e = TEST_PROPS.keys(); e.hasMoreElements();) {
+      key = e.nextElement();
+      value = TEST_PROPS.get(key);
+      switch (key) {
+      case APITEST:
+        break;
+      case BASIC_AUTH_PASSWD:
+      case BASIC_AUTH_REALM:
+        break;
+      case BASIC_AUTH_USER:
+        String user = TEST_PROPS.get(Property.BASIC_AUTH_USER);
+        String password = TEST_PROPS.get(Property.BASIC_AUTH_PASSWD);
+        String base64 = new BASE64Encoder()
+            .encode((user + ":" + password).getBytes());
+        testCase.addHeader("Authorization", " Basic " + base64);
+        break;
+      case CONTENT:
+        // req.setContent(value);
+        testCase.setEntity(value);
+        break;
+      case DONOTUSEServletName:
+        break;
+      case EXPECT_RESPONSE_BODY:
+        // FIXME
+        // setExpectResponseBody(false);
+        break;
+      case EXPECTED_HEADERS:
+        testCase.addExpectedHeader(value);
+        break;
+      case FOLLOW_REDIRECT:
+        TestUtil.logTrace("##########Found redirect Property");
+        _redirect = true;
+        break;
+      case GOLDENFILE:
+        StringBuffer sb = new StringBuffer(50);
+        sb.append(_tsHome).append(GOLDENFILEDIR);
+        sb.append(_generalURI).append(SL);
+        sb.append(value);
+        testCase.setGoldenFilePath(sb.toString());
+        break;
+      case IGNORE_BODY:
+        // FIXME
+        // setIgnoreResponseBody(true);
+        testCase.setGoldenFilePath(null);
+        break;
+      case IGNORE_STATUS_CODE:
+        testCase.setExpectedStatusCode("-1");
+        break;
+      case REASON_PHRASE:
+        testCase.setExpectedReasonPhrase(value);
+        break;
+      case REQUEST:
+        testCase.setUrlRequest(value);
+        break;
+      case REQUEST_HEADERS:
+        String[] headers = splitByColon(value);
+        for (String header : headers) {
+          String[] split = header.split(":", 2);
+          testCase.addHeader(split[0].trim(), split[1].trim());
+        }
+        break;
+      case RESPONSE_MATCH:
+        // setResponseMatch(TEST_PROPS.getProperty(key));
+        break;
+      case SAVE_STATE:
+        _saveState = true;
+        break;
+      case SEARCH_STRING:
+        value = testCase.getTextCaser().getCasedText(value);
+        testCase.setResponseSearchString(value);
+        break;
+      case SEARCH_STRING_IGNORE_CASE:
+        testCase.setResponseSearchStringIgnoreCase(value);
+        break;
+      case STANDARD:
+        break;
+      case STATUS_CODE:
+        if (value.contains("|"))
+          testCase.setStrategy(
+              CheckOneOfStatusesTokenizedValidator.class.getName());
+        testCase.setExpectedStatusCode(value);
+        break;
+      case STRATEGY:
+        testCase.setStrategy(value);
+        break;
+      case TEST_NAME:
+        // testName = TEST_PROPS.getProperty(key);
+        break;
+      case UNEXPECTED_HEADERS:
+        testCase.addUnexpectedHeader(value);
+        break;
+      case UNEXPECTED_RESPONSE_MATCH:
+        testCase.setUnexpectedResponseSearchString(value);
+        break;
+      case UNORDERED_SEARCH_STRING:
+        value = testCase.getTextCaser().getCasedText(value);
+        testCase.setUnorderedSearchString(value);
+        break;
+      case USE_SAVED_STATE:
+        _useSavedState = true;
+        break;
+      }
+    }
+  }
+
+  /**
+   * Replaces String#split("|"), as it does not split for special character '|'
+   */
+  protected static String[] splitByColon(String value) {
+    int colonIndex = -1, lastIndex = 0;
+    LinkedList<String> list = new LinkedList<String>();
+    while ((colonIndex = value.indexOf('|', lastIndex)) != -1) {
+      list.add(value.substring(lastIndex, colonIndex));
+      lastIndex = colonIndex + 1;
+    }
+    if (lastIndex < value.length())
+      list.add(value.substring(lastIndex));
+    return list.toArray(new String[list.size()]);
+  }
+
+  /**
+   * <PRE>
+   * Invokes a test based on the properties
+   * stored in TEST_PROPS.  Once the test has completed,
+   * the properties in TEST_PROPS will be cleared.
+   * </PRE>
+   *   
+   *  @throws Fault
+   *           If an error occurs during the test run
+   */
+  protected void invoke() throws Fault {
+    TestUtil.logTrace("[JAXRSCommonClient] invoke");
+    try {
+      getTestCase().setPort(_port);
+      getTestCase().setHostname(_hostname);
+      setTestProperties(testCase);
+      TestUtil.logTrace("[JAXRSCommonClient] EXECUTING");
+      if (_useSavedState && _state != null) {
+        testCase.getRequest().setState(_state);
+      }
+      if (_redirect != false) {
+        TestUtil.logTrace("##########Call setFollowRedirects");
+        testCase.getRequest().setFollowRedirects(_redirect);
+      }
+      testCase.execute();
+      isTestCaseAfterInvocation = true;
+      if (_saveState) {
+        _state = testCase.getResponse().getState();
+      }
+    } catch (TestFailureException tfe) {
+      Throwable t = tfe.getRootCause();
+      if (t != null) {
+        TestUtil.logErr("Root cause of Failure: " + t.getMessage(), t);
+      }
+      throw new Fault("[JAXRSCommonClient] " + _testName
+          + " failed!  Check output for cause of failure.", tfe);
+    } finally {
+      _useSavedState = false;
+      _saveState = false;
+      _redirect = false;
+      clearTestProperties();
+      clients.add(testCase.client);
+    }
+  }
+
+  @Override
+  public void cleanup() throws Fault{
+    super.cleanup();
+    // The client.close has to be called on cleanup, because after invoke,
+    // some methods are called and resources might not be available then
+    // (javadoc: Close client instance and all it's associated resources).
+    // Since more invoke() invocations are possible, the clients are stored
+    // in a list to be closed on cleanup
+    for (Client c : clients)
+      c.close();
+    clients.clear();
+  }
+
+  /*public void setup(String[] args, Properties p) {
+    super.setup(args, p);
+    String property = System.getProperty("cts.tmp");
+    if (property != null)
+      System.setProperty("java.io.tmpdir", property);
+  }*/
+
+  protected JaxrsWebTestCase getTestCase() {
+    if (testCase == null || isTestCaseAfterInvocation) {
+      testCase = new JaxrsWebTestCase();
+      isTestCaseAfterInvocation = false;
+    }
+    return testCase;
+  }
+
+  @Override
+  protected String buildRequest(Request type, String... path) {
+    getTestCase().setRequestType(type.name());
+    StringBuilder sb = new StringBuilder();
+    sb.append(_contextRoot == null ? "" : _contextRoot).append(SL);
+    for (String segment : path)
+      sb.append(segment);
+    return sb.toString();
+  }
+
+  @Override
+  @Deprecated
+  protected void setProperty(String key, String value) {
+    super.setProperty(key, value);
+  }
+
+  @Override
+  @Deprecated
+  protected String buildRequest(String type, String... path) {
+    return super.buildRequest(type, path);
+  }
+
+  protected Response getResponse() {
+    return testCase.getJaxrsResponse();
+  }
+
+  @Override
+  protected String getResponseBody() {
+    return getResponseBody(String.class);
+  }
+
+  protected <T> T getResponseBody(Class<T> clazz) {
+    return getResponse().readEntity(clazz);
+  }
+
+  public List<Object> getProvidersToRegister() {
+    return getTestCase().getProvidersToRegister();
+  }
+
+  public void addProvider(Object providerToRegister) {
+    getTestCase().addProviderToRegister(providerToRegister);
+  }
+
+  @Override
+  protected String[] getResponseHeaders() throws Fault {
+    return getMetadata(getResponse().getMetadata());
+  }
+
+  /**
+   * Calls setHeader(Property.REQUEST_HEADERS, header : values);
+   * 
+   * @param header
+   *          Recommended one of HttpHeaders static values
+   * @param values
+   *          the value[1]value[2]...value[n] which are to be assigned to
+   *          {@code}header name
+   */
+  protected void addHeader(String header, String... values) {
+    StringBuilder sb = new StringBuilder();
+    sb.append(header).append(":");
+    if (values != null)
+      for (String value : values)
+        sb.append(value);
+    setProperty(Property.REQUEST_HEADERS, sb.toString());
+  }
+
+  /**
+   * This method is typically used to transform http headers metadata into a
+   * String array. The headers are in a form of java class instance, e.g.
+   * stream(!), or String
+   * 
+   * @param metadata
+   * @return
+   */
+  public static String[] getMetadata(MultivaluedMap<String, Object> metadata) {
+    String[] headers = new String[metadata.size()];
+    int i = 0;
+    for (Entry<String, List<Object>> e : metadata.entrySet()) {
+      headers[i++] = e.getKey() + ":" + listToString(e.getValue());
+    }
+    return headers;
+  }
+
+  @Override
+  protected Status getResponseStatusCode() {
+    return Status.fromStatusCode(getResponse().getStatus());
+  }
+
+  protected void setRequestContentEntity(Object object) {
+    getTestCase().setEntity(object);
+  }
+
+  public static <T> String listToString(List<T> list) {
+    StringBuilder sb = new StringBuilder();
+    for (T s : list)
+      sb.append(s).append(" ");
+    return sb.toString().trim();
+  }
+
+  protected void printClientCall(boolean print) {
+    getTestCase().setPrintClientCall(print);
+  }
+
+  protected void setAsynchronousProcessing() {
+    getTestCase().setProcessingType(Execution.ASYNCHRONOUS);
+  }
+
+  protected void setPrintEntity(boolean printEntity) {
+    getTestCase().setPrintEntity(printEntity);
+  }
+
+  protected void bufferEntity(boolean buffer) {
+    getTestCase().bufferEntity(buffer);
+  }
+
+  protected void setTextCaser(TextCaser caser) {
+    getTestCase().setTextCaser(caser);
+  }
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/JaxrsWebTestCase.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/JaxrsWebTestCase.java
new file mode 100644
index 0000000..82cb16c
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/JaxrsWebTestCase.java
@@ -0,0 +1,525 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common.client;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.Future;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+import jakarta.ws.rs.tck.common.webclient.TestFailureException;
+import jakarta.ws.rs.tck.common.webclient.WebTestCase;
+import jakarta.ws.rs.tck.common.webclient.http.HttpRequest;
+import jakarta.ws.rs.tck.common.webclient.http.HttpResponse;
+import jakarta.ws.rs.tck.common.webclient.validation.ValidationFactory;
+import jakarta.ws.rs.tck.common.webclient.validation.ValidationStrategy;
+
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.client.Invocation;
+import jakarta.ws.rs.client.InvocationCallback;
+import jakarta.ws.rs.client.WebTarget;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Request;
+import jakarta.ws.rs.core.Response;
+
+/**
+ * Replaces WebTestCase to be used with JAXRS client instead of apache client
+ * 
+ * @author supol
+ */
+public class JaxrsWebTestCase extends WebTestCase {
+
+  /**
+   * The JAXRS request instance
+   */
+  protected Request request;
+
+  /**
+   * The JAXRS response instance
+   */
+  protected Response response;
+
+  /**
+   * GET, PUT, OPTIONS, ...
+   */
+  protected String requestType;
+
+  /**
+   * The URL of the Request
+   */
+  protected String urlRequest;
+
+  /**
+   * The HTTP content entity. A MessageBodyWriter<entity.getClass()> needs to be
+   * registered if not a standard entity type supported by JAXRS
+   */
+  protected Object entity;
+
+  /**
+   * port of the server
+   */
+  protected int port;
+
+  /**
+   * host name of the server
+   */
+  protected String hostname;
+
+  /**
+   * HTTP header list
+   */
+  protected Map<String, String> headerMap;
+
+  /**
+   * Apache HTTP response mock
+   */
+  protected HttpResponse _response;
+
+  /**
+   * print the response entity
+   */
+  protected boolean printEntity = true;
+
+  /**
+   * buffer the returned entity
+   */
+  protected boolean bufferEntity = false;
+
+  /**
+   * Provider logging the request and response
+   */
+  protected Object loggingFilter;
+
+  /**
+   * other providers, such as MessageBodyReader, or MessageBodyWriter
+   */
+  protected List<Object> providersToRegister;
+
+  /**
+   * Strategy to use when validating the test case against the server's
+   * response.
+   */
+  protected ValidationStrategy strategy = null;
+
+  /**
+   * Show the call client code, used to be printed when report issues
+   */
+  protected boolean printClientCall = false;
+
+  /**
+   * Upper case, lower case, or exact text matching?
+   */
+  protected TextCaser textCaser = TextCaser.NONE;
+
+  /**
+   * Type of execution
+   */
+  protected enum Execution {
+    SYNCHRONOUS, ASYNCHRONOUS
+  }
+
+  /**
+   * Runnable to run while asynchronous
+   */
+  protected Runnable asyncRunnable;
+
+  /**
+   * Execution type instance
+   */
+  protected Execution executionType = Execution.SYNCHRONOUS;
+
+  /**
+   * Client instance here not to be garbage collected before end of test.
+   */
+  protected Client client;
+
+  public JaxrsWebTestCase() {
+    strategy = ValidationFactory.getInstance(TOKENIZED_STRATEGY);
+    headerMap = new HashMap<String, String>();
+    providersToRegister = new LinkedList<Object>();
+    closeClient();
+  }
+
+  /**
+   * Sets the validation strategy for this test case instance.
+   * 
+   * @param validator
+   *          - the fully qualified class name of the response validator to use.
+   */
+  public void setStrategy(String validator) {
+    ValidationStrategy strat = ValidationFactory.getInstance(validator);
+    if (strat != null) {
+      strategy = strat;
+    } else {
+      StringBuilder sb = new StringBuilder();
+      sb.append("[WebTestCase][WARNING] An attempt was made to use a ");
+      sb.append("non-existing validator (");
+      sb.append(validator);
+      sb.append(").  Falling back to the TokenizedValidator");
+      TestUtil.logMsg(sb.toString());
+    }
+  }
+
+  // /**
+  //  * Executes the test case.
+  //  * 
+  //  * @throws TestFailureException
+  //  *           if the test fails for any reason.
+  //  * @throws IllegalStateException
+  //  *           if no request was configured or if no Validator is available at
+  //  *           runtime.
+  //  */
+  // public void execute() throws TestFailureException {
+  //   verifyValidationStrategy();
+  //   verifySettings();
+  //   try {
+  //     String url = logClientRequestAndGetUrl();
+
+  //     client = getClientWithRegisteredProviders();
+  //     WebTarget target = client.target(url.toString());
+  //     Invocation i = buildRequest(target);
+  //     response = invoke(i);
+  //     if (bufferEntity)
+  //       response.bufferEntity();
+  //   } catch (Throwable t) {
+  //     String message = t.getMessage();
+
+  //     StringBuilder sb = new StringBuilder();
+  //     sb.append("[FATAL] Unexpected failure during test execution.\n");
+  //     // print client call code to report into JIRA when needed
+  //     sb.append(printClientCall().toString());
+  //     // Inherited message
+  //     sb.append((message == null ? t.toString() : message));
+
+  //     throw new TestFailureException(sb.toString(), t);
+  //   }
+
+  //   // Validate this test case instance
+  //   if (!strategy.validate(this)) {
+  //     throw new TestFailureException("Test FAILED!");
+  //   }
+  // }
+
+  public void closeClient() {
+    if (client != null)
+      client.close();
+    client = null;
+  }
+
+  protected void verifyValidationStrategy() {
+    // If no strategy instance is available (strange, but has happened),
+    // fail.
+    try {
+      getStrategy();
+    } catch (NullPointerException e) {
+      throw new IllegalStateException("[FATAL] No Validator available.");
+    }
+  }
+
+  protected void verifySettings() throws TestFailureException {
+    if (hostname == null)
+      throw new TestFailureException("No hostname set");
+    if (port == 0)
+      throw new TestFailureException("Port not set");
+    if (requestType == null)
+      throw new TestFailureException("No request method set");
+    if (urlRequest == null)
+      throw new TestFailureException("No resource url request set");
+  }
+
+  // /**
+  //  * @return Client with all providers already registered
+  //  */
+  // protected Client getClientWithRegisteredProviders() {
+  //   Client client = ClientBuilder.newClient();
+  //   client.register(new JdkLoggingFilter(isPrintedEntity()));
+  //   for (Object o : providersToRegister)
+  //     if (o instanceof Class)
+  //       client.register((Class<?>) o); // otherwise it does not work
+  //     else
+  //       client.register(o);
+  //   return client;
+  // }
+
+  protected String logClientRequestAndGetUrl() {
+    StringBuilder url = new StringBuilder();
+    url.append("http://").append(hostname).append(":").append(port);
+    url.append(urlRequest);
+
+    StringBuilder msg = new StringBuilder();
+    msg.append("[Request] Dispatching request: '").append(requestType)
+        .append(" ").append(url).append("' to target server at '")
+        .append(hostname).append(":").append(port).append("'");
+    TestUtil.logMsg(msg.toString());
+    TestUtil.logMsg("###############################");
+
+    if (printClientCall)
+      TestUtil.logMsg(printClientCall().toString());
+
+    return url.toString();
+  }
+
+  /**
+   * Log java code executed
+   */
+  protected StringBuilder printClientCall() {
+    StringBuilder url = new StringBuilder();
+    url.append("http://").append(hostname).append(":").append(port);
+    url.append(urlRequest);
+
+    StringBuilder sb = new StringBuilder();
+    // print client call code to report into JIRA when needed
+    sb.append("Client client = ClientFactory.newClient();\n");
+    for (Object o : providersToRegister) {
+      sb.append("client.configuration().register(");
+      if (o instanceof Class)
+        sb.append(((Class<?>) o).getName()).append(".class");
+      else
+        sb.append(o.getClass().getName());
+      sb.append(");\n");
+    }
+    sb.append("WebTarget target = client.target(\"").append(url.toString())
+        .append("\");\n");
+    sb.append("Invocation.Builder builder;\n");
+    sb.append("builder = target.request(\"").append(getAcceptMediaType())
+        .append("\");\n");
+    for (Entry<String, String> entry : headerMap.entrySet()) {
+      sb.append("builder.header(\"").append(entry.getKey()).append("\",\"")
+          .append(entry.getValue()).append("\");\n");
+    }
+    sb.append("Invocation i;\n");
+    sb.append("i=builder.build(\"").append(requestType).append("\"");
+    if (entity != null)
+      sb.append(",").append("Entity.entity(").append(entity.toString())
+          .append(",").append(getContentType());
+    sb.append(");\n");
+    sb.append("i.invoke();\n");
+
+    return sb;
+  }
+
+  /**
+   * Build Invocation
+   */
+  protected Invocation buildRequest(WebTarget target) {
+    Invocation.Builder builder;
+    builder = target.request(getAcceptMediaType());
+    for (Entry<String, String> entry : headerMap.entrySet()) {
+      if (!entry.getKey().equals("Accept"))
+        builder.header(entry.getKey(), entry.getValue());
+    }
+    Invocation i;
+    if (entity != null) {
+      if (entity instanceof Entity)
+        i = builder.build(requestType, (Entity<?>) entity);
+      else
+        i = builder.build(requestType, Entity.entity(entity, getContentType()));
+      TestUtil.logMsg("[Request] Adding entity: " + entity);
+    } else
+      i = builder.build(requestType);
+    return i;
+  }
+
+  /**
+   * Invoke the invocation synchronously, or asynchronously
+   */
+  protected Response invoke(Invocation invocation) throws TestFailureException {
+    Response response = null;
+    switch (executionType) {
+    case SYNCHRONOUS:
+      response = invocation.invoke();
+      break;
+    case ASYNCHRONOUS:
+      int cnt = 0;
+      try {
+        final boolean[] buffered = { false };
+        InvocationCallback<Response> callback = new InvocationCallback<Response>() {
+          @Override
+          public void completed(Response res) {
+            try {
+              JaxrsWebTestCase.this.response = res;
+              // buffer before stream is closed
+              getResponse().getResponseBodyAsString();
+              buffered[0] = true;
+            } catch (IOException e) {
+              throw new RuntimeException(e);
+            }
+          }
+
+          @Override
+          public void failed(Throwable throwable) {
+            throw new RuntimeException(throwable);
+          }
+        };
+        Future<Response> future = invocation.submit(callback);
+        while (!buffered[0] && cnt++ < 50) {
+          Thread.sleep(100L);
+        }
+        response = future.get();
+        // response = invocation.submit().get();
+      } catch (Exception e) {
+        throw new TestFailureException(e);
+      }
+      if (cnt > 49) {
+        throw new TestFailureException(
+            "Invocation callback has not been called within 5 second");
+      }
+    }
+    return response;
+  }
+
+  /**
+   * Get media type in Request Content Type
+   */
+  protected String getAcceptMediaType() {
+    String media = headerMap.get("Accept");
+    if (media == null)
+      media = MediaType.WILDCARD;
+    return media;
+  }
+
+  /**
+   * Get media type in Request Content Type
+   */
+  protected String getContentType() {
+    String media = headerMap.get("Content-Type");
+    if (media == null)
+      media = MediaType.WILDCARD;
+    return media;
+  }
+
+  // ---------------------------------------------------------------------
+  // Apache adaptor methods
+
+  @Override
+  public HttpRequest getRequest() {
+    if (super.getRequest() == null) {
+      StringBuilder sb = new StringBuilder();
+      sb.append(requestType).append(" ").append(urlRequest).append("/");
+      sb.append(" HTTP/1.1");
+      super.setRequest(new ApacheRequestAdapter(sb.toString(), hostname, port));
+    }
+    return super.getRequest();
+  }
+
+  @Override
+  public synchronized HttpResponse getResponse() {
+    if (_response == null) {
+      _response = new ApacheResponseAdapter(response, hostname, port,
+          textCaser);
+    }
+    return _response;
+  }
+
+  // ---------------------------------------------------------------------
+  // Getters and Setters
+
+  public void setRequestType(String requestType) {
+    this.requestType = requestType;
+  }
+
+  public int getPort() {
+    return port;
+  }
+
+  public void setPort(int port) {
+    this.port = port;
+  }
+
+  public String getHostname() {
+    return hostname;
+  }
+
+  public void setHostname(String hostname) {
+    this.hostname = hostname;
+  }
+
+  public String getUrlRequest() {
+    return urlRequest;
+  }
+
+  public void setUrlRequest(String urlRequest) {
+    this.urlRequest = urlRequest;
+  }
+
+  public void addHeader(String name, String value) {
+    headerMap.put(name, value);
+  }
+
+  public Response getJaxrsResponse() {
+    return response;
+  }
+
+  public void setEntity(Object entity) {
+    this.entity = entity;
+  }
+
+  /**
+   * Returns the Request for this particular test case.
+   * 
+   * @return Request of this test case
+   */
+  public Request getJaxrsRequest() {
+    return request;
+  }
+
+  public boolean isPrintedEntity() {
+    return printEntity;
+  }
+
+  /**
+   * Set whether the entity is to be printed in trace log or not;
+   */
+  public void setPrintEntity(boolean printEntity) {
+    this.printEntity = printEntity;
+  }
+
+  public void bufferEntity(boolean bufferEntity) {
+    this.bufferEntity = bufferEntity;
+  }
+
+  public List<Object> getProvidersToRegister() {
+    return providersToRegister;
+  }
+
+  public void addProviderToRegister(Object providerToRegister) {
+    this.providersToRegister.add(providerToRegister);
+  }
+
+  public void setPrintClientCall(boolean print) {
+    printClientCall = print;
+  }
+
+  public void setProcessingType(Execution type) {
+    executionType = type;
+  }
+
+  public TextCaser getTextCaser() {
+    return textCaser;
+  }
+
+  public void setTextCaser(TextCaser textCaser) {
+    this.textCaser = textCaser;
+  }
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/JdkLoggingFilter.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/JdkLoggingFilter.java
new file mode 100644
index 0000000..971f9c4
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/JdkLoggingFilter.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common.client;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Formatter;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import jakarta.annotation.Priority;
+import jakarta.ws.rs.client.ClientRequestContext;
+import jakarta.ws.rs.client.ClientRequestFilter;
+import jakarta.ws.rs.client.ClientResponseContext;
+import jakarta.ws.rs.client.ClientResponseFilter;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.ext.Provider;
+
+@Provider
+@Priority(Integer.MAX_VALUE)
+public class JdkLoggingFilter extends Formatter
+    implements ClientRequestFilter, ClientResponseFilter {
+
+  private static final Logger LOGGER = Logger
+      .getLogger(JdkLoggingFilter.class.getName());
+
+  private static final String REQUEST_PREFIX = ">> ";
+
+  private static final String RESPONSE_PREFIX = "<< ";
+
+  //
+  private final DateFormat df = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss");
+
+  private final Logger logger;
+
+  private boolean printEntity = true;
+
+  /**
+   * Create a logging filter logging the request and response to a default JDK
+   * logger, named as the fully qualified class name of this class.
+   */
+  public JdkLoggingFilter(boolean printEntity) {
+    this(LOGGER, printEntity);
+  }
+
+  /**
+   * Create a logging filter with custom logger and custom settings of entity
+   * logging.
+   * 
+   * @param logger
+   *          the logger to log requests and responses.
+   * @param printEntity
+   *          if true, entity will be logged as well.
+   */
+  public JdkLoggingFilter(Logger logger, boolean printEntity) {
+    this.logger = logger;
+    this.printEntity = printEntity;
+
+    ConsoleHandler handler = new ConsoleHandler();
+    logger.setUseParentHandlers(false);
+    handler.setFormatter(this);
+
+    // Set handler only once
+    if (logger.getHandlers().length == 0)
+      logger.addHandler(handler);
+  }
+
+  @Override
+  public void filter(ClientRequestContext arg0,
+      ClientResponseContext responseContext) throws IOException {
+    printResponseLine(responseContext.getStatus());
+    printPrefixedHeaders(RESPONSE_PREFIX, responseContext.getHeaders());
+    if (printEntity && responseContext.hasEntity()) {
+      List<String> entity = replaceEntityStream(responseContext);
+      log(RESPONSE_PREFIX, entity);
+    }
+
+  }
+
+  @Override
+  public void filter(ClientRequestContext requestContext) throws IOException {
+    printRequestLine(requestContext.getMethod(), requestContext.getUri());
+    MultivaluedMap<String, Object> headers = requestContext.getHeaders();
+    StringBuilder sb = new StringBuilder().append(REQUEST_PREFIX);
+    for (String header : JaxrsCommonClient.getMetadata(headers)) {
+      if (sb.length() > REQUEST_PREFIX.length())
+        sb.append(", ");
+      sb.append(header);
+    }
+    log(sb);
+    if (printEntity && requestContext.hasEntity()) {
+      log(new StringBuilder().append(REQUEST_PREFIX)
+          .append(requestContext.getEntity().toString()));
+    }
+  }
+
+  private static List<String> replaceEntityStream(ClientResponseContext ctx)
+      throws IOException {
+    List<String> entity = null;
+    if (ctx.hasEntity()) {
+      InputStream is = ctx.getEntityStream();
+      entity = readEntityFromStream(is);
+      ByteArrayInputStream bais = new ByteArrayInputStream(
+          linesToBytes(entity));
+      ctx.setEntityStream(bais);
+    }
+    return entity;
+  }
+
+  private static byte[] linesToBytes(List<String> lines) {
+    StringBuilder sb = new StringBuilder();
+    for (Iterator<String> i = lines.iterator(); i.hasNext();) {
+      sb.append(i.next());
+      if (i.hasNext())
+        sb.append("\n");
+    }
+    return sb.toString().getBytes();
+  }
+
+  private static List<String> readEntityFromStream(InputStream is)
+      throws IOException {
+    String entity;
+    List<String> lines = new LinkedList<String>();
+    InputStreamReader isr = new InputStreamReader(is);
+    BufferedReader br = new BufferedReader(isr);
+    while ((entity = br.readLine()) != null)
+      lines.add(entity);
+    return lines;
+  }
+
+  private void log(StringBuilder b) {
+    if (logger != null)
+      logger.info(b.append("\n").toString());
+  }
+
+  private void log(String prefix, List<String> rows) {
+    if (logger != null && rows != null)
+      for (String row : rows)
+        logger.info(new StringBuilder().append(prefix).append(row).append("\n")
+            .toString());
+  }
+
+  private void printRequestLine(String method, URI uri) {
+    StringBuilder sb = new StringBuilder();
+    sb.append(REQUEST_PREFIX).append(method).append(" ")
+        .append(uri.toASCIIString());
+    log(sb);
+  }
+
+  private void printResponseLine(int status) {
+    StringBuilder sb = new StringBuilder();
+    sb.append(RESPONSE_PREFIX).append(status).append(" ")
+        .append(Response.Status.fromStatusCode(status).name());
+    log(sb);
+  }
+
+  private void printPrefixedHeaders(final String prefix,
+      Map<String, List<String>> headers) {
+    for (Map.Entry<String, List<String>> e : headers.entrySet()) {
+      StringBuilder sb = new StringBuilder();
+      List<String> val = e.getValue();
+      String header = e.getKey();
+
+      if (val.size() == 1) {
+        sb.append(prefix).append(header).append(": ").append(val.get(0));
+      } else {
+        StringBuilder sb2 = new StringBuilder();
+        for (String s : val) {
+          if (sb2.length() != 0)
+            sb2.append(',');
+          sb2.append(s);
+        }
+        sb.append(prefix).append(header).append(": ").append(sb2.toString());
+      }
+      if (sb.length() != 0)
+        log(sb);
+    }
+
+  }
+
+  @Override
+  public String format(LogRecord record) {
+    StringBuilder sb = new StringBuilder();
+    sb.append(df.format(new Date(record.getMillis()))).append(":  ")
+        .append("TRACE: [WIRE] - ");
+    sb.append(formatMessage(record));
+    return sb.toString();
+  }
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/TextCaser.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/TextCaser.java
new file mode 100644
index 0000000..4e454da
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/client/TextCaser.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common.client;
+
+/**
+ * Standard WebTestCase can search strings in an order case sensitive, case
+ * insensitive or not in order case sensitive. When there is a need to match not
+ * in order and case insensitive, this class is used.
+ */
+public enum TextCaser {
+  UPPER, NONE, LOWER;
+
+  /**
+   * Get the text upper cased, lower cased, or unchanged, depending on current
+   * TextCaser value
+   */
+  public final String getCasedText(String text) {
+    String ret = null;
+    switch (this) {
+    case UPPER:
+      ret = text.toUpperCase();
+      break;
+    case LOWER:
+      ret = text.toLowerCase();
+      break;
+    case NONE:
+      ret = text;
+      break;
+    }
+    return ret;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/impl/SinglevaluedMap.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/impl/SinglevaluedMap.java
new file mode 100644
index 0000000..4cd4db4
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/impl/SinglevaluedMap.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+ package jakarta.ws.rs.tck.common.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import jakarta.ws.rs.core.MultivaluedMap;
+
+public class SinglevaluedMap<K, V> implements MultivaluedMap<K, V> {
+
+  Map<K, V> map = new HashMap<K, V>();
+
+  @Override
+  public int size() {
+    return map.size();
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return map.isEmpty();
+  }
+
+  @Override
+  public boolean containsKey(Object key) {
+    return map.containsKey(key);
+  }
+
+  @Override
+  public boolean containsValue(Object value) {
+    return map.containsValue(value);
+  }
+
+  @Override
+  public List<V> get(Object key) {
+    return Collections.singletonList(map.get(key));
+  }
+
+  @Override
+  public List<V> put(K key, List<V> value) {
+    V v;
+    if (value == null)
+      v = map.put(key, null);
+    else
+      v = map.put(key, value.iterator().next());
+    return Collections.singletonList(v);
+  }
+
+  @Override
+  public List<V> remove(Object key) {
+    return Collections.singletonList(map.remove(key));
+  }
+
+  @Override
+  public void putAll(Map<? extends K, ? extends List<V>> m) {
+    for (Entry<? extends K, ? extends List<V>> e : m.entrySet())
+      map.put(e.getKey(), e.getValue().iterator().next());
+  }
+
+  @Override
+  public void clear() {
+    map.clear();
+  }
+
+  @Override
+  public Set<K> keySet() {
+    return map.keySet();
+  }
+
+  @Override
+  public Collection<List<V>> values() {
+    Collection<List<V>> col = new ArrayList<List<V>>();
+    for (V v : map.values())
+      col.add(Collections.singletonList(v));
+    return col;
+  }
+
+  @Override
+  public Set<java.util.Map.Entry<K, List<V>>> entrySet() {
+    Map<K, List<V>> adapter = new HashMap<K, List<V>>();
+    for (Entry<K, V> e : map.entrySet())
+      adapter.put(e.getKey(), Collections.singletonList(e.getValue()));
+    return adapter.entrySet();
+  }
+
+  @Override
+  public void add(K key, V value) {
+    map.put(key, value);
+  }
+
+  @Override
+  public V getFirst(K key) {
+    return map.get(key);
+  }
+
+  @Override
+  public void putSingle(K key, V value) {
+    map.put(key, value);
+  }
+
+  @Override
+  public void addAll(K key, V... value) {
+    if (value != null)
+      putSingle(key, value[0]);
+  }
+
+  @Override
+  public void addAll(K arg0, List<V> arg1) {
+    if (arg1.iterator().hasNext())
+      putSingle(arg0, arg1.iterator().next());
+  }
+
+  @Override
+  public void addFirst(K arg0, V arg1) {
+    putSingle(arg0, arg1);
+  }
+
+  @Override
+  public boolean equalsIgnoreValueOrder(MultivaluedMap<K, V> arg0) {
+    for (java.util.Map.Entry<K, List<V>> set : arg0.entrySet()) {
+      if (!map.containsKey(set.getKey()))
+        return false;
+      if (!map.containsValue(set.getValue().iterator().next()))
+        return false;
+    }
+    return true;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/impl/TRACE.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/impl/TRACE.java
new file mode 100644
index 0000000..8139699
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/impl/TRACE.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common.impl;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jakarta.ws.rs.HttpMethod;
+
+@HttpMethod("TRACE")
+@Target(value = ElementType.METHOD)
+@Retention(value = RetentionPolicy.RUNTIME)
+public @interface TRACE {
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/provider/StringBean.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/provider/StringBean.java
new file mode 100644
index 0000000..6b6a51b
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/provider/StringBean.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common.provider;
+
+/**
+ * This is the object which standard implementation does not have a provider
+ * for, even though its some simple String holder. It can also be used as
+ * mutable string.
+ */
+public class StringBean {
+  private String header;
+
+  public String get() {
+    return header;
+  }
+
+  public void set(String header) {
+    this.header = header;
+  }
+
+  @Override
+  public String toString() {
+    return "StringBean. To get a value, use rather #get() method.";
+  }
+
+  public StringBean(String header) {
+    super();
+    this.header = header;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/provider/StringBeanHeaderDelegate.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/provider/StringBeanHeaderDelegate.java
new file mode 100644
index 0000000..283770c
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/provider/StringBeanHeaderDelegate.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common.provider;
+
+import jakarta.ws.rs.ext.Provider;
+import jakarta.ws.rs.ext.RuntimeDelegate.HeaderDelegate;
+
+@Provider
+public class StringBeanHeaderDelegate implements HeaderDelegate<StringBean> {
+
+  @Override
+  public StringBean fromString(String string) throws IllegalArgumentException {
+    return new StringBean(string);
+  }
+
+  @Override
+  public String toString(StringBean bean) throws IllegalArgumentException {
+    return bean.get();
+  }
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/provider/StringBeanRuntimeDelegate.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/provider/StringBeanRuntimeDelegate.java
new file mode 100644
index 0000000..309d8cb
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/provider/StringBeanRuntimeDelegate.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+ package jakarta.ws.rs.tck.common.provider;
+
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Link;
+import jakarta.ws.rs.core.EntityPart;
+import jakarta.ws.rs.core.Response.ResponseBuilder;
+import jakarta.ws.rs.core.UriBuilder;
+import jakarta.ws.rs.core.Variant.VariantListBuilder;
+import jakarta.ws.rs.ext.RuntimeDelegate;
+
+import java.util.concurrent.CompletionStage;
+
+import jakarta.ws.rs.SeBootstrap;
+import jakarta.ws.rs.SeBootstrap.Instance;
+
+public class StringBeanRuntimeDelegate extends RuntimeDelegate {
+
+  public StringBeanRuntimeDelegate(RuntimeDelegate orig) {
+    super();
+    this.original = orig;
+    assertNotStringBeanRuntimeDelegate(orig);
+  }
+
+  private RuntimeDelegate original;
+
+  @Override
+  public <T> T createEndpoint(Application arg0, Class<T> arg1)
+      throws IllegalArgumentException, UnsupportedOperationException {
+    return original.createEndpoint(arg0, arg1);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public <T> HeaderDelegate<T> createHeaderDelegate(Class<T> arg0)
+      throws IllegalArgumentException {
+    if (arg0 == StringBean.class)
+      return (HeaderDelegate<T>) new StringBeanHeaderDelegate();
+    else
+      return original.createHeaderDelegate(arg0);
+  }
+
+  @Override
+  public ResponseBuilder createResponseBuilder() {
+    return original.createResponseBuilder();
+  }
+
+  @Override
+  public UriBuilder createUriBuilder() {
+    return original.createUriBuilder();
+  }
+
+  @Override
+  public VariantListBuilder createVariantListBuilder() {
+    return original.createVariantListBuilder();
+  }
+
+  @Override
+  public EntityPart.Builder createEntityPartBuilder(String partName) {
+    return original.createEntityPartBuilder(partName);
+  }
+
+  @Override
+  public CompletionStage<Instance> bootstrap(Application application, SeBootstrap.Configuration configuration) {
+    return original.bootstrap(application, configuration);
+  }
+
+  @Override
+  public SeBootstrap.Configuration.Builder createConfigurationBuilder() {
+    return original.createConfigurationBuilder();
+  }
+
+  public RuntimeDelegate getOriginal() {
+    return original;
+  }
+
+  public static final void assertNotStringBeanRuntimeDelegate() {
+    RuntimeDelegate delegate = RuntimeDelegate.getInstance();
+    assertNotStringBeanRuntimeDelegate(delegate);
+  }
+
+  public static final//
+  void assertNotStringBeanRuntimeDelegate(RuntimeDelegate delegate) {
+    if (delegate instanceof StringBeanRuntimeDelegate) {
+      StringBeanRuntimeDelegate sbrd = (StringBeanRuntimeDelegate) delegate;
+      if (sbrd.getOriginal() != null)
+        RuntimeDelegate.setInstance(sbrd.getOriginal());
+      throw new RuntimeException(
+          "RuntimeDelegate.getInstance() is StringBeanRuntimeDelegate");
+    }
+  }
+
+  @Override
+  public Link.Builder createLinkBuilder() {
+    return original.createLinkBuilder();
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/util/Data.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/util/Data.java
new file mode 100644
index 0000000..d433614
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/util/Data.java
@@ -0,0 +1,65 @@
+/*
+*
+* The Apache Software License, Version 1.1
+*
+* Copyright (c) 2018, 2021 Oracle and/or its affiliates. All rights reserved.
+* Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
+* reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in
+*    the documentation and/or other materials provided with the
+*    distribution.
+*
+* 3. The end-user documentation included with the redistribution, if
+*    any, must include the following acknowlegement:
+*       "This product includes software developed by the
+*        Apache Software Foundation (http://www.apache.org/)."
+*    Alternately, this acknowlegement may appear in the software itself,
+*    if and wherever such third-party acknowlegements normally appear.
+*
+* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
+*    Foundation" must not be used to endorse or promote products derived
+*    from this software without prior written permission. For written
+*    permission, please contact apache@apache.org.
+*
+* 5. Products derived from this software may not be called "Apache"
+*    nor may "Apache" appear in their names without prior written
+*    permission of the Apache Group.
+*
+* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+* SUCH DAMAGE.
+* ====================================================================
+*
+* This software consists of voluntary contributions made by many
+* individuals on behalf of the Apache Software Foundation.  For more
+* information on the Apache Software Foundation, please see
+* <http://www.apache.org/>.
+*
+*/
+
+package jakarta.ws.rs.tck.common.util;
+
+public final class Data {
+
+  public static final String PASSED = "Test PASSED";
+
+  public static final String FAILED = "Test FAILED";
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/util/Holder.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/util/Holder.java
new file mode 100644
index 0000000..d5df129
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/util/Holder.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common.util;
+
+public class Holder<TYPE> {
+
+  public Holder() {
+  };
+
+  public Holder(TYPE type) {
+    set(type);
+  }
+
+  public TYPE value;
+
+  public void set(TYPE value) {
+    this.value = value;
+  }
+
+  public TYPE get() {
+    return value;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/util/JaxrsUtil.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/util/JaxrsUtil.java
new file mode 100644
index 0000000..3663433
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/util/JaxrsUtil.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common.util;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.lang.reflect.Array;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.TimeZone;
+
+public abstract class JaxrsUtil {
+
+  public static final//
+  String readFromStream(InputStream stream) throws IOException {
+    InputStreamReader isr = new InputStreamReader(stream);
+    return readFromReader(isr);
+  }
+
+  public static final//
+  String readFromReader(Reader reader) throws IOException {
+    BufferedReader br = new BufferedReader(reader);
+    String entity = br.readLine();
+    br.close();
+    return entity;
+  }
+
+  public static final//
+  String readFromFile(File file) throws IOException {
+    FileReader reader = new FileReader(file);
+    return readFromReader(reader);
+  }
+
+  public static final <T> //
+  String iterableToString(String separator, Iterable<T> collection) {
+    if (collection != null)
+      return iterableToString(separator, collection.iterator());
+    return "";
+  }
+
+  public static final <T> //
+  String iterableToString(String separator, Iterator<T> iterator) {
+    StringBuilder sb = new StringBuilder();
+    while (iterator.hasNext()) {
+      T item = iterator.next();
+      if (item != null) {
+        String appendable = item.toString();
+        sb.append(appendable);
+        if (iterator.hasNext())
+          sb.append(separator);
+      }
+    }
+    return sb.toString();
+  }
+
+  public static final <T> //
+  String enumerationToString(String separator, Enumeration<T> enumeration) {
+    StringBuilder sb = new StringBuilder();
+    if (enumeration != null)
+      while (enumeration.hasMoreElements()) {
+        T item = enumeration.nextElement();
+        if (item != null) {
+          String appendable = item.toString();
+          sb.append(appendable);
+          if (enumeration.hasMoreElements())
+            sb.append(separator);
+        }
+      }
+    return sb.toString();
+  }
+
+  public static final //
+  String iterableToString(String separator, Object... collection) {
+    StringBuilder sb = new StringBuilder();
+    if (collection != null)
+      for (int i = 0; i != collection.length; i++) {
+        Object item = collection[i];
+        if (item != null) {
+          String appendable = item.toString();
+          sb.append(appendable);
+          if (i != collection.length - 1)
+            sb.append(separator);
+        }
+      }
+    return sb.toString();
+  }
+
+  public static final TimeZone findTimeZoneInDate(String date) {
+    StringBuilder sb = new StringBuilder();
+    StringBuilder dateBuilder = new StringBuilder(date.trim()).reverse();
+    int index = 0;
+    char c;
+    while ((c = dateBuilder.charAt(index++)) != ' ') {
+      sb.append(c);
+    }
+    TimeZone timezone = TimeZone.getTimeZone(sb.reverse().toString());
+    return timezone;
+  }
+
+  public static final String mapToString(java.util.Map<?, ?> map) {
+    StringBuilder sb = new StringBuilder();
+    if (map != null)
+      for (Object key : map.keySet()) {
+        sb.append("[").append(key).append(" : ");
+        Object value = map.get(key);
+        sb.append(toString(value)).append("]");
+      }
+    return sb.toString();
+  }
+
+  public static final DateFormat createDateFormat(TimeZone timezone) {
+    SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z",
+        Locale.US);
+    sdf.setTimeZone(timezone);
+    return sdf;
+  }
+
+  public static String toString(Object object) {
+    String to = null;
+    if (object == null)
+      to = "null";
+    else if (Iterable.class.isInstance(object))
+      to = iterableToString(" ", (Iterable<?>) object);
+    else if (Enumeration.class.isInstance(object))
+      to = enumerationToString(" ", (Enumeration<?>) object);
+    else if (java.util.Map.class.isInstance(object))
+      to = mapToString((java.util.Map<?, ?>) object);
+    else if (Iterator.class.isInstance(object))
+      to = iterableToString(" ", (Iterator<?>) object);
+    else if (Array.class.isInstance(object))
+      to = iterableToString(" ", (Object[]) object);
+    else if (object.getClass().isArray())
+      to = primitiveArrayToString(object);
+    else
+      to = String.valueOf(object);
+    return to;
+  }
+
+  public static String primitiveArrayToString(Object array) {
+    String to = null;
+    if (array == null)
+      to = "null";
+    else if (array.getClass().isArray()) {
+      String sarray = array.toString();
+      if (sarray.startsWith("[I"))
+        to = Arrays.toString((int[]) array);
+      else if (sarray.startsWith("[B"))
+        to = Arrays.toString((byte[]) array);
+      else if (sarray.startsWith("[J"))
+        to = Arrays.toString((long[]) array);
+      else if (sarray.startsWith("[C"))
+        to = Arrays.toString((char[]) array);
+      else if (sarray.startsWith("[S"))
+        to = Arrays.toString((short[]) array);
+      else if (sarray.startsWith("[F"))
+        to = Arrays.toString((float[]) array);
+      else if (sarray.startsWith("[D"))
+        to = Arrays.toString((double[]) array);
+      else if (sarray.startsWith("[Z"))
+        to = Arrays.toString((boolean[]) array);
+      else if (sarray.startsWith("[L"))
+        to = Arrays.toString((Object[]) array);
+    } else
+      to = String.valueOf(array);
+    return to;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/util/LinkedHolder.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/util/LinkedHolder.java
new file mode 100644
index 0000000..c9c3479
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/util/LinkedHolder.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common.util;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ * Hold multiple instances of TYPE in a {@link LinkedList} structure, last one
+ * accessible by {@link #get()}.
+ * 
+ * @param <TYPE>
+ */
+public class LinkedHolder<TYPE> extends Holder<TYPE> implements Iterable<TYPE> {
+
+  private LinkedList<TYPE> list = new LinkedList<TYPE>();
+
+  public LinkedHolder(TYPE type) {
+    add(type);
+  }
+
+  public LinkedHolder() {
+  }
+
+  public void add(TYPE value) {
+    list.add(value);
+    super.set(value);
+  }
+
+  /**
+   * Replace the last item in the list
+   */
+  @Override
+  public void set(TYPE value) {
+    if (list.size() != 0) {
+      list.set(list.size() - 1, value);
+      super.set(value);
+    }
+    if (value == null) {
+      super.set(null);
+    } else {
+      add(value);
+    }
+  }
+
+  public TYPE get(int index) {
+    if (index >= list.size())
+      return null;
+    return list.get(index);
+  }
+
+  public int size() {
+    return list.size();
+  }
+
+  public void clear() {
+    super.set(null);
+    list.clear();
+  }
+
+  @Override
+  public Iterator<TYPE> iterator() {
+    return list.iterator();
+  }
+
+  public LinkedList<TYPE> asList() {
+    return list;
+  }
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/Goldenfile.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/Goldenfile.java
new file mode 100644
index 0000000..cdd8023
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/Goldenfile.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.common.webclient;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+
+/**
+ * A representation of a Goldenfile that may be used by a particular test case.
+ */
+
+public class Goldenfile {
+
+  /*
+   * Message to be returned if the goldenfile cannot be located.
+   */
+  private static final byte[] NOTFOUND = "NO GOLDENFILE FOUND".getBytes();
+
+  /*
+   * Message to be returned if the goldenfile doesn't have read permissions.
+   */
+  private static final byte[] NOPERM = "INSUFFICIENT PERMISSIONS".getBytes();
+
+  /*
+   * Goldenfile represented by this object.
+   */
+  private File _file = null;
+
+  /*
+   * Error message to return by public methods if the file is not found or the
+   * user has insufficient permissions.
+   */
+  private byte[] _errMessage = null;
+
+  /*
+   * Goldenfile length
+   */
+  private long _length = 0L;
+
+  /*
+   * Encoding
+   */
+  private String _encoding = null;
+
+  /**
+   * Creates a new GoldenFile based on the fully qualified filename provided.
+   *
+   * @param path
+   *          Fully qualified file name
+   * @param encoding
+   *          to use when reading the goldenfile
+   */
+  public Goldenfile(String path, String encoding) {
+    _file = new File(path);
+    if (!_file.exists()) {
+      TestUtil.logTrace("[GoldenFile] Goldenfile: " + path + ", not found!");
+      _errMessage = NOTFOUND;
+      _file = null;
+    } else if (!_file.canRead()) {
+      _errMessage = NOPERM;
+      _file = null;
+    } else {
+      _length = _file.length();
+      _encoding = encoding;
+    }
+  }
+
+  /*
+   * public methods
+   * ========================================================================
+   */
+
+  /**
+   * Returns the length of the Goldenfile.
+   *
+   * @return long length
+   */
+  public long getLength() {
+    return _length;
+  }
+
+  /**
+   * Returns the byte content of the specified goldenfile using the charset
+   * encoding specified in the response from the server.
+   *
+   * @return the goldenfile as a byte array
+   * @throws IOException
+   *           if an error occurs processing the file.
+   */
+  public byte[] getGoldenFileAsBytes() throws IOException {
+    if (_file != null) {
+      return getGoldenFileAsString().getBytes();
+    } else {
+      return _errMessage;
+    }
+  }
+
+  /**
+   * Retuns a string representation of the specified goldenfile using the
+   * charset encoding specified in the response from the server.
+   *
+   * @return the goldenfile as a String.
+   * @throws IOException
+   *           if an error occurs processing the file.
+   */
+  public String getGoldenFileAsString() throws IOException {
+    String gf = null;
+    if (_file != null) {
+      TestUtil.logTrace(
+          "[Goldenfile] Loading goldenfile using " + "encoding: " + _encoding);
+      FileInputStream in = new FileInputStream(_file);
+      gf = Util.getEncodedStringFromStream(in, _encoding);
+      in.close();
+    } else {
+      gf = new String(_errMessage);
+    }
+    return gf;
+  }
+
+  /**
+   * Returns the goldenfile as an InputStream using the charset encoding
+   * specified in the response from the server.
+   *
+   * @return goldenfile as an InputStream
+   * @throws IOException
+   *           If an error occurs processing the file.
+   */
+  public InputStream getGoldenFileAsStream() throws IOException {
+    if (_file != null) {
+      return new ByteArrayInputStream(getGoldenFileAsBytes());
+    } else {
+      return new ByteArrayInputStream(_errMessage);
+    }
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/TestCase.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/TestCase.java
new file mode 100644
index 0000000..45b716e
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/TestCase.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.common.webclient;
+
+/**
+ * This interface defines a base set of methods required used by a TS test case.
+ */
+public interface TestCase {
+
+  /**
+   * Executes the test case.
+   *
+   * @throws TestFailureException
+   *           if the test fails for any reason.
+   */
+  public void execute() throws TestFailureException;
+
+  /**
+   * Sets the name of the test case.
+   *
+   * @param name
+   *          of the test case
+   */
+  public void setName(String name);
+
+  /**
+   * Returns the name of this test case.
+   *
+   * @return test case name
+   */
+  public String getName();
+
+  /**
+   * Sets the state for this test case. This state will differ from
+   * implementation to implementation.
+   *
+   * @param state
+   *          test state
+   */
+  public void setState(Object state);
+
+  /**
+   * Returns the state of the test case. The state returned could possibly
+   * differ depending on when this method is called and when the test case has
+   * been executed.
+   */
+  public Object getState();
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/TestFailureException.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/TestFailureException.java
new file mode 100644
index 0000000..c71f384
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/TestFailureException.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.common.webclient;
+
+/**
+ * Signifies a failure at some point during a test cycle.
+ */
+public class TestFailureException extends java.lang.Exception {
+
+  private static final long serialVersionUID = -4651996590051941456L;
+
+  /**
+   * Creates a new instance of <code>TestFailureException</code> without a
+   * detailed message.
+   */
+  public TestFailureException() {
+  }
+
+  /**
+   * Creates a new instance of <code>TestFailureException</code> containing the
+   * root cause of the test failure.
+   * 
+   * @param t
+   *          - root cause
+   */
+  public TestFailureException(Throwable t) {
+    super(t);
+  }
+
+  /**
+   * Creates a new instance of <code>TestFailureException</code> with the
+   * specified detail message.
+   * 
+   * @param msg
+   *          - the detail message.
+   */
+  public TestFailureException(String msg) {
+    super(msg);
+  }
+
+  /**
+   * Creates a new instance of <code>TestFailureException</code> with the
+   * specified detail message, and the root cause of the test failure
+   * 
+   * @param msg
+   *          - the detail message
+   * @param t
+   *          - root cause
+   */
+  public TestFailureException(String msg, Throwable t) {
+    super(msg, t);
+  }
+
+  /**
+   * Returns, if any, the root cause of this Exception.
+   * 
+   * @return the root cause of this exception, or null
+   */
+  public Throwable getRootCause() {
+    return getCause();
+  }
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/Util.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/Util.java
new file mode 100644
index 0000000..604e6cf
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/Util.java
@@ -0,0 +1,234 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000 The Apache Software Foundation.  All rights
+ * Copyright (c) 2000 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package jakarta.ws.rs.tck.common.webclient;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import jakarta.ws.rs.tck.lib.util.BASE64Encoder;
+
+public class Util {
+
+  /**
+   * Zeros
+   */
+  private static final String ZEROS = "00000000";
+
+  /**
+   * short pad size
+   */
+  private static final int SHORTPADSIZE = 4;
+
+  /**
+   * byte pad size
+   */
+  private static final int BYTEPADSIZE = 2;
+
+  /** Creates new Util */
+  private Util() {
+  }
+
+  /*
+   * public methods
+   * ========================================================================
+   */
+
+  /**
+   * BASE64 encodes the provided string.
+   * 
+   * @return BASE64 encoded string.
+   */
+  public static String getBase64EncodedString(String value) {
+    BASE64Encoder encoder = new BASE64Encoder();
+    return encoder.encode(value.getBytes());
+  }
+
+  /**
+   * Returns a charset encoded string based on the provided InputStream and
+   * charset encoding.
+   *
+   * @return encoding string
+   */
+  public static String getEncodedStringFromStream(InputStream in, String enc)
+      throws IOException {
+    BufferedReader bin = new BufferedReader(new InputStreamReader(in, enc));
+    StringBuffer sb = new StringBuffer(128);
+    for (int ch = bin.read(); ch != -1; ch = bin.read()) {
+      sb.append((char) ch);
+    }
+    return sb.toString();
+  }
+
+  /**
+   * <code>getHexValue</code> displays a formatted hex representation of the
+   * passed byte array. It also allows for only a specified offset and length of
+   * a particular array to be returned.
+   *
+   * @param bytes
+   *          <code>byte[]</code> array to process.
+   * @param pos
+   *          <code>int</code> specifies offset to begin processing.
+   * @param len
+   *          <code>int</code> specifies the number of bytes to process.
+   * @return <code>String</code> formatted hex representation of processed
+   *         array.
+   */
+  public static String getHexValue(byte[] bytes, int pos, int len) {
+    StringBuffer outBuf = new StringBuffer(bytes.length * 2);
+    int bytesPerLine = 36;
+    int cnt = 1;
+    int groups = 4;
+    int curPos = pos;
+    int linePos = 1;
+    boolean displayOffset = true;
+
+    while (len-- > 0) {
+      if (displayOffset) {
+
+        outBuf.append("\n" + paddedHexString(pos, SHORTPADSIZE, true) + ": ");
+        displayOffset = false;
+      }
+
+      outBuf.append(paddedHexString((int) bytes[pos], BYTEPADSIZE, false));
+      linePos += 2; // Byte is padded to 2 characters
+
+      if ((cnt % 4) == 0) {
+        outBuf.append(" ");
+        linePos++;
+      }
+
+      // Now display the characters that are printable
+      if ((cnt % (groups * 4)) == 0) {
+        outBuf.append(" ");
+
+        while (curPos <= pos) {
+          if (!Character.isWhitespace((char) bytes[curPos])) {
+            outBuf.append((char) bytes[curPos]);
+          } else {
+            outBuf.append(".");
+          }
+
+          curPos++;
+        }
+
+        curPos = pos + 1;
+        linePos = 1;
+        displayOffset = true;
+      }
+
+      cnt++;
+      pos++;
+    }
+
+    // pad out the line with spaces
+    while (linePos++ <= bytesPerLine) {
+      outBuf.append(" ");
+    }
+
+    outBuf.append(" ");
+    // Now display the printable characters for the trailing bytes
+    while (curPos < pos) {
+      if (!Character.isWhitespace((char) bytes[curPos])) {
+        outBuf.append((char) bytes[curPos]);
+      } else {
+        outBuf.append(".");
+      }
+
+      curPos++;
+    }
+
+    return outBuf.toString();
+  }
+
+  /*
+   * private methods
+   * ========================================================================
+   */
+
+  /**
+   * <code>paddedHexString</code> pads the passed value based on the specified
+   * wordsize and the value of the prefixFlag.
+   *
+   * @param val
+   *          an <code>int</code> value
+   * @param wordsize
+   *          an <code>int</code> value
+   * @param prefixFlag
+   *          a <code>boolean</code> value
+   * @return a <code>String</code> value
+   */
+  private static String paddedHexString(int val, int wordsize,
+      boolean prefixFlag) {
+
+    String prefix = prefixFlag ? "0x" : "";
+    String hexVal = Integer.toHexString(val);
+
+    if (hexVal.length() > wordsize)
+      hexVal = hexVal.substring(hexVal.length() - wordsize);
+
+    return (prefix + (wordsize > hexVal.length()
+        ? ZEROS.substring(0, wordsize - hexVal.length())
+        : "") + hexVal);
+  }
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/WebTestCase.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/WebTestCase.java
new file mode 100644
index 0000000..27c1c3a
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/WebTestCase.java
@@ -0,0 +1,590 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.common.webclient;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.HttpState;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+import jakarta.ws.rs.tck.common.webclient.http.HttpRequest;
+import jakarta.ws.rs.tck.common.webclient.http.HttpResponse;
+import jakarta.ws.rs.tck.common.webclient.validation.ValidationFactory;
+import jakarta.ws.rs.tck.common.webclient.validation.ValidationStrategy;
+import jakarta.ws.rs.tck.common.webclient.TestFailureException;
+
+/**
+ * A TestCase implementation for HTTP-based testing. This allows the user to set
+ * criteria for test success which will be compared against the response from
+ * the server.
+ */
+public class WebTestCase implements TestCase {
+
+  /**
+   * Tokenized response validation strategy
+   */
+  public static final String TOKENIZED_STRATEGY = "jakarta.ws.rs.tck.common.webclient.validation.TokenizedValidator";
+
+  /**
+   * Whitespace response validation strategy
+   */
+  public static final String WHITESPACE_STRATEGY = "jakarta.ws.rs.tck.common.webclient.validation.WhitespaceValidator";
+
+  /**
+   * The request for this case.
+   */
+  private HttpRequest _request = null;
+
+  /**
+   * The server's response.
+   */
+  private HttpResponse _response = null;
+
+  // use HttpMethod instances to store test
+  // case headers that are expected or not
+  // expected.
+
+  /**
+   * Storage for headers that are expected in the response
+   */
+  private Map<String, Header> _expected = null;
+
+  /**
+   * Storage for headers that are not expected in the response
+   */
+  private Map<String, Header> _unexpected = null;
+
+  /**
+   * Expected response status code.
+   */
+  private String _statusCode = null;
+
+  /**
+   * Expected response reason phrase.
+   */
+  private String _reasonPhrase = null;
+
+  /**
+   * Path to goldenfile.
+   */
+  private String _goldenfilePath = null;
+
+  /**
+   * A List of strings that will be searched for in the response in the order
+   * they appear in the list.
+   */
+  private List<String> _searchStrings = null;
+
+  /**
+   * A List of case insensitive strings that will be searched for in the
+   * response in the order they appear in the list.
+   */
+  private List<String> _searchStringsNoCase = null;
+
+  /**
+   * A List of strings that will be search for in the response with no attention
+   * paid to the order they appear.
+   */
+  private List<String> _unorderedSearchStrings = null;
+
+  /**
+   * A List of strings that should not be in the server's response.
+   */
+  private List<String> _uSearchStrings = null;
+
+  /**
+   * Indicates whether a response body should be expected or not.
+   */
+  private boolean _expectResponseBody = true;
+
+  /**
+   * Strategy to use when validating the test case against the server's
+   * response.
+   */
+  private ValidationStrategy _strategy = null;
+
+  /**
+   * Logical name for test case.
+   */
+  private String _name = "Test Case";
+
+  /**
+   * Creates a new instance of WebTestCase By default, a new WebTestCase
+   * instance will use the TokenizedValidator to verify the response with the
+   * configured properties of the test case.
+   */
+  public WebTestCase() {
+    _strategy = ValidationFactory.getInstance(TOKENIZED_STRATEGY);
+  }
+
+  /*
+   * public methods
+   * ========================================================================
+   */
+  /**
+   * Executes the test case.
+   *
+   * @throws TestFailureException
+   *           if the test fails for any reason.
+   * @throws IllegalStateException
+   *           if no request was configured or if no Validator is available at
+   *           runtime.
+   */
+  public void execute() throws TestFailureException {
+
+    // If no request was created, we can't run.
+    if (_request == null) {
+      throw new IllegalStateException("[FATAL] HttpRequest is null.");
+    }
+
+    // If no stragey instance is available (strange, but has happened),
+    // fail.
+    if (_strategy == null) {
+      throw new IllegalStateException("[FATAL] No Validator available.");
+    }
+
+    try {
+      _response = _request.execute();
+    } catch (Throwable t) {
+      String message = t.getMessage();
+      throw new TestFailureException("[FATAL] Unexpected failure during "
+          + "test execution." + (message == null ? t.toString() : message), t);
+    }
+
+    // Validate this test case instance
+    if (!_strategy.validate(this)) {
+      throw new TestFailureException("Test FAILED!");
+    }
+
+  }
+
+  /**
+   * Sets the status code to be expected in the response from the server, i.e.
+   * 500 or 404, etc.
+   *
+   * @param statusCode
+   *          the expected status code
+   */
+  public void setExpectedStatusCode(String statusCode) {
+    _statusCode = statusCode;
+  }
+
+  /**
+   * Sets the reason phrase to be expected in the response from the server.
+   *
+   * @param reasonPhrase
+   *          the expected reason-phrase
+   */
+  public void setExpectedReasonPhrase(String reasonPhrase) {
+    _reasonPhrase = reasonPhrase;
+  }
+
+  /**
+   * Adds a header that is to be expected in the response from the server.
+   *
+   * @param header
+   *          in the format of <headername>:<value> (test:foo)
+   */
+  public void addExpectedHeader(String header) {
+    if (_expected == null) {
+      _expected = new HashMap<String, Header>();
+    }
+    addHeader(_expected, header);
+  }
+
+  /**
+   * Sets the path to the goldenfile the test case should use.
+   *
+   * @param gfPath
+   *          a fully qualified path including filename.
+   */
+  public void setGoldenFilePath(String gfPath) {
+    _goldenfilePath = gfPath;
+  }
+
+  /**
+   * Sets the request that should be dispatched by this test case.
+   *
+   * @param request
+   *          the HTTP request used for this test case
+   */
+  public void setRequest(HttpRequest request) {
+    _request = request;
+  }
+
+  /**
+   * Adds a header that is should not be in the server's response.
+   *
+   * @param header
+   *          in the format of <headername>:<value> (test:foo)
+   */
+  public void addUnexpectedHeader(String header) {
+    if (_unexpected == null) {
+      _unexpected = new HashMap<String, Header>();
+    }
+    addHeader(_unexpected, header);
+  }
+
+  /**
+   * Enables/Disables an assertion that a response body is present.
+   *
+   * @param value
+   *          a value of true will enable the assertion.
+   */
+  public void setAssertNoResponseBody(boolean value) {
+  }
+
+  /**
+   * Sets a string that will be scanned for and expected in the response body
+   * from the server.
+   *
+   * If multiple search strings are required, one can either call this method
+   * for each string, or pass in one string with pipe <code>|<code> delimiting
+   * the individual search strings within the large string.
+   *
+   * @param searchString
+   *          a string expected in the server's response body
+   */
+  public void setResponseSearchString(String searchString) {
+    if (_searchStrings == null) {
+      _searchStrings = new ArrayList<String>();
+    }
+    addSearchStrings(_searchStrings, searchString);
+  }
+
+  /**
+   * Sets a string that will be scanned for and expected in the response body
+   * from the server.
+   *
+   * If multiple search strings are required, one can either call this method
+   * for each string, or pass in one string with pipe <code>|<code> delimiting
+   * the individual search strings within the large string.
+   *
+   * @param searchString
+   *          a case insensitive string expected in the server's response body
+   */
+  public void setResponseSearchStringIgnoreCase(String searchString) {
+    if (_searchStringsNoCase == null) {
+      _searchStringsNoCase = new ArrayList<String>();
+    }
+    addSearchStrings(_searchStringsNoCase, searchString);
+  }
+
+  /**
+   * Sets a string that will be scanned for and should not be present in the
+   * response body from the server.
+   *
+   * If multiple search strings are required, one can either call this method
+   * for each string, or pass in one string with pipe <code>|<code> delimiting
+   * the individual search strings within the large string.
+   *
+   * @param searchString
+   *          a string that is not expected in the server's response body
+   */
+  public void setUnexpectedResponseSearchString(String searchString) {
+    if (_uSearchStrings == null) {
+      _uSearchStrings = new ArrayList<String>();
+    }
+    addSearchStrings(_uSearchStrings, searchString);
+  }
+
+  /**
+   * Sets a string or series of strings that will be searched for in the
+   * response. If multiple search strings are required, one can either call this
+   * method for each string, or pass in one string with pipe <code>|<code>
+   * delimiting the individual search strings within the large string.
+   *
+   * @param searchString
+   *          a string that is not expected in the server's response body
+   */
+  public void setUnorderedSearchString(String searchString) {
+    if (_unorderedSearchStrings == null) {
+      _unorderedSearchStrings = new ArrayList<String>();
+    }
+    addSearchStrings(_unorderedSearchStrings, searchString);
+  }
+
+  /**
+   * Returns the list of search strings.
+   * 
+   * @return the list of search strings.
+   */
+  public List<String> getUnorderedSearchStrings() {
+    return _unorderedSearchStrings;
+  }
+
+  /**
+   * Returns the response for this particular test case.
+   *
+   * @return an HttpResponse object
+   */
+  public HttpResponse getResponse() {
+    return _response;
+  }
+
+  /**
+   * Returns an array of Header objects that are expected to be found in the
+   * responst.
+   *
+   * @return an array of headers
+   */
+  public Header[] getExpectedHeaders() {
+    if (_expected == null) {
+      return null;
+    }
+    return _expected.values().toArray(new Header[_expected.size()]);
+  }
+
+  /**
+   * Returns an array of Header objects that are not expected to be found in the
+   * responst.
+   *
+   * @return an array of headers
+   */
+  public Header[] getUnexpectedHeaders() {
+    if (_unexpected == null) {
+      return null;
+    }
+    return _unexpected.values().toArray(new Header[_unexpected.size()]);
+  }
+
+  /**
+   * Returns the status code expected to be found in the server's response
+   *
+   * @return status code
+   */
+  public String getStatusCode() {
+    return _statusCode;
+  }
+
+  /**
+   * Returns the reason phrase that is expected to be found in the server's
+   * response.
+   *
+   * @return reason phrase
+   */
+  public String getReasonPhrase() {
+    return _reasonPhrase;
+  }
+
+  /**
+   * Returns the configured list of strings that will be used when scanning the
+   * server's response.
+   *
+   * @return list of Strings
+   */
+  public List<String> getSearchStrings() {
+    if (_searchStrings == null) {
+      return null;
+    }
+    return _searchStrings;
+  }
+
+  /**
+   * Returns the configured list of strings that will be used when scanning the
+   * server's response.
+   *
+   * @return list of case insensitive Strings
+   */
+  public List<String> getSearchStringsNoCase() {
+    if (_searchStringsNoCase == null) {
+      return null;
+    }
+    return _searchStringsNoCase;
+  }
+
+  /**
+   * Returns the configured list of strings that will be used when scanning the
+   * server's response (these strings are not expected in the response).
+   *
+   * @return list of Strings
+   */
+  public List<String> getUnexpectedSearchStrings() {
+    if (_uSearchStrings == null) {
+      return null;
+    }
+    return _uSearchStrings;
+  }
+
+  /**
+   * Returns an indicator on whether a response body is expected or not.
+   *
+   * @return boolean value
+   */
+  public boolean getExpectResponseBody() {
+    return _expectResponseBody;
+  }
+
+  /**
+   * Returns the HttpRequest for this particular test case.
+   *
+   * @return HttpRequest of this test case
+   */
+  public HttpRequest getRequest() {
+    return _request;
+  }
+
+  /**
+   * Returns the path to the goldenfile.
+   *
+   * @return path to the goldenfile
+   */
+  public String getGoldenfilePath() {
+    return _goldenfilePath;
+  }
+
+  /**
+   * Returns the state for this particular test case.
+   *
+   * @return test state
+   */
+  public Object getState() {
+    if (_response != null) {
+      return _response.getState();
+    } else {
+      // an initial request for state
+      return _request.getState();
+    }
+  }
+
+  /**
+   * Sets the state for this test case.
+   *
+   * @param state
+   *          test state
+   */
+  public void setState(Object state) {
+    _request.setState((HttpState) state);
+  }
+
+  /**
+   * Sets a logical name for this test case.
+   *
+   * @param name
+   *          the logical name for this test
+   */
+  public void setName(String name) {
+    _name = name;
+  }
+
+  /**
+   * Returns the logical name for this test case.
+   *
+   * @return test name
+   */
+  public String getName() {
+    return _name;
+  }
+
+  /**
+   * Sets the validation strategy for this test case instance.
+   *
+   * @param validator
+   *          - the fully qualified class name of the response validator to use.
+   */
+  public void setStrategy(String validator) {
+    ValidationStrategy strat = ValidationFactory.getInstance(validator);
+    if (strat != null) {
+      _strategy = strat;
+    } else {
+      TestUtil.logMsg("[WebTestCase][WARNING] An attempt was made to use a "
+          + "non-existing validator (" + validator + ")"
+          + ".  Falling back to the TokenizedValidator");
+    }
+  }
+
+  /**
+   * Returns the class name of the response validator used.
+   *
+   * @return the fully qualified class of the validator used
+   */
+  public String getStrategy() {
+    return _strategy.getClass().getName();
+  }
+
+  /*
+   * Private Methods
+   * ===========================================================================
+   */
+
+  /**
+   * Utility method to add headers to test case holder objects.
+   *
+   * @param map
+   *          the object in which to add header to
+   * @param headerString
+   *          String representation of a header in the form of
+   *          <headername>:<value>
+   */
+  private void addHeader(Map<String, Header> map, String headerString) {
+    TestUtil.logTrace(
+        "[WebTestCase] addHeader utility method called: " + headerString);
+    StringTokenizer st = new StringTokenizer(headerString, "|");
+    while (st.hasMoreTokens()) {
+      String head = st.nextToken();
+      int colIdx = head.indexOf(':');
+      String name = head.substring(0, colIdx).trim();
+      String value = head.substring(colIdx + 1).trim();
+      TestUtil
+          .logTrace("[WebTestCase] Adding test header: " + name + ", " + value);
+      Header header = map.get(name);
+      if (header != null) {
+        map.put(name, createNewHeader(value, header));
+      } else {
+        map.put(name, new Header(name, value));
+      }
+    }
+  }
+
+  /**
+   * Creates a new header based of the provided header and value.
+   * 
+   * @param newValue
+   *          - the new value to add to an existing header
+   * @param header
+   *          - the original header
+   * @return new Header
+   */
+  private Header createNewHeader(String newValue, Header header) {
+    String oldValue = header.getValue();
+    return new Header(header.getName(), oldValue + ", " + newValue);
+  }
+
+  /**
+   * Adds a search string to the provided list
+   * 
+   * @param stringList
+   *          - list to add the string to
+   * @param s
+   *          - the search string
+   */
+  private void addSearchStrings(List<String> stringList, String s) {
+    StringTokenizer st = new StringTokenizer(s, "|");
+    while (st.hasMoreTokens()) {
+      stringList.add(st.nextToken());
+    }
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/ALLOWHandler.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/ALLOWHandler.java
new file mode 100644
index 0000000..5fc2685
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/ALLOWHandler.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2008, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+package jakarta.ws.rs.tck.common.webclient.handler;
+
+import java.util.StringTokenizer;
+
+import org.apache.commons.httpclient.Header;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+
+public class ALLOWHandler implements Handler {
+
+  private static final Handler HANDLER = new ALLOWHandler();
+
+  private static final String DELIM = "##";
+
+  private ALLOWHandler() {
+  }
+
+  public static Handler getInstance() {
+    return HANDLER;
+  }
+
+  public boolean invoke(Header configuredHeader, Header responseHeader) {
+    String ALLOWHeader = responseHeader.getValue().toLowerCase();
+    String expectedValues = configuredHeader.getValue().toLowerCase()
+        .replace(" ", "");
+
+    TestUtil.logTrace("[ALLOWHandler] ALLOW header received: " + ALLOWHeader);
+
+    StringTokenizer conf = new StringTokenizer(expectedValues, ",");
+    while (conf.hasMoreTokens()) {
+      String token = conf.nextToken();
+      String token1 = token;
+
+      if ((ALLOWHeader.indexOf(token) < 0)
+          && (ALLOWHeader.indexOf(token1) < 0)) {
+        TestUtil.logErr("[ALLOWHandler] Unable to find '" + token
+            + "' within the ALLOW header returned by the server.");
+        return false;
+      } else {
+        TestUtil.logTrace("[ALLOWHandler] Found expected value, '" + token
+            + "' in ALLOW header returned by server.");
+      }
+    }
+    return true;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/ContentTypeHandler.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/ContentTypeHandler.java
new file mode 100644
index 0000000..3840a64
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/ContentTypeHandler.java
@@ -0,0 +1,153 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000 The Apache Software Foundation.  All rights
+ * Copyright (c) 2000 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package jakarta.ws.rs.tck.common.webclient.handler;
+
+import org.apache.commons.httpclient.Header;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+
+/**
+ * <PRE>
+ * When invoked, the content-type header
+ * will be appropriately handled.  It allows
+ * flexible checking of control values against
+ * the response which could be in the form of:
+ *    content-type; charset
+ *      -or-
+ *    conent-type
+ * </PRE>
+ */
+public class ContentTypeHandler implements Handler {
+
+  private static Handler handler = new ContentTypeHandler();
+
+  /**
+   * Creates new ContentTypeHandler
+   */
+  private ContentTypeHandler() {
+  }
+
+  /*
+   * public methods
+   * ========================================================================
+   */
+
+  /**
+   * Returns an instance of this handler.
+   */
+  public static Handler getInstance() {
+    return handler;
+  }
+
+  /**
+   * Invokes handler logic.
+   * 
+   * @param configuredHeader
+   *          the user configured header
+   * @param responseHeader
+   *          the response header from the server
+   * @return True if the passed match, otherwise false
+   */
+  public boolean invoke(Header configuredHeader, Header responseHeader) {
+    boolean ret = false;
+    TestUtil.logTrace("[ContentTypeHandler] ContentTypeHandler invoked.");
+    String configVal = configuredHeader.getValue().trim();
+    String responseVal = responseHeader.getValue().trim();
+    int colIdx = configVal.indexOf(';');
+    if (colIdx < 0) {
+      // Info we're interested in : type/subtype
+
+      // check response Content-Type header to see what format
+      // it's in.
+      int rColIdx = responseVal.indexOf(';');
+      if (rColIdx < 0) {
+        // Type and subtype, i.e. type/subtype are to be compared
+        // case insensitively.
+        if (configVal.equalsIgnoreCase(responseVal)) {
+          ret = true;
+        }
+      } else {
+        if (configVal.equalsIgnoreCase(responseVal.substring(0, rColIdx))) {
+          ret = true;
+        }
+      }
+    } else {
+      // Info we're interested in : type/subtype; parameter=value
+
+      int rColIdx = responseVal.indexOf(';');
+      if (rColIdx > -1) {
+        String confTypeSubType = configVal.substring(0, colIdx).trim();
+        String responseTypeSubType = responseVal.substring(0, rColIdx).trim();
+        String confParameter = configVal.substring(colIdx + 1).trim();
+        String responseParameter = (responseVal.substring(rColIdx + 1).trim())
+            .replaceAll(" ", "");
+        // compare type/subtype in a case insensitive manner
+        if (confTypeSubType.equalsIgnoreCase(responseTypeSubType)) {
+          // next validate the parameter in a case insensitive manner
+          if (confParameter.equalsIgnoreCase(responseParameter)) {
+            ret = true;
+          }
+        }
+      }
+    }
+    return ret;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/DefaultHandler.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/DefaultHandler.java
new file mode 100644
index 0000000..4ef41af
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/DefaultHandler.java
@@ -0,0 +1,145 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000 The Apache Software Foundation.  All rights
+ * Copyright (c) 2000 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package jakarta.ws.rs.tck.common.webclient.handler;
+
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.HeaderElement;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+
+/**
+ * <PRE>
+ * The default handler will handle any
+ * header that doesn't have a configured handler.
+ * </PRE>
+ */
+public class DefaultHandler implements Handler {
+
+  private static Handler handler = new DefaultHandler();
+
+  /**
+   * Creates new DefaultHandler
+   */
+  private DefaultHandler() {
+  }
+
+  /*
+   * public methods
+   * ========================================================================
+   */
+
+  /**
+   * Returns an instance of this handler.
+   */
+  public static Handler getInstance() {
+    return handler;
+  }
+
+  /**
+   * Invokes handler logic.
+   * 
+   * @param configuredHeader
+   *          the user configured header
+   * @param responseHeader
+   *          the response header from the server
+   * @return True if the passed match, otherwise false
+   */
+  public boolean invoke(Header configuredHeader, Header responseHeader) {
+
+    TestUtil.logTrace("[DefaulHandler] DefaultHandler invoked.");
+
+    return areHeadersEqual(configuredHeader, responseHeader);
+  }
+
+  /**
+   * Utility method to determine equality of two Header objects
+   * 
+   * @param h1
+   *          first header
+   * @param h2
+   *          second header
+   * @return true if the headers are equal, otherwise false
+   */
+  protected boolean areHeadersEqual(Header h1, Header h2) {
+
+    HeaderElement[] h1Values = h1.getElements();
+    HeaderElement[] h2Values = h2.getElements();
+
+    if (h1Values.length == h2Values.length) {
+      for (HeaderElement h1Value : h1Values) {
+        String h1Val = h1Value.getName();
+        boolean found = false;
+        for (HeaderElement h2Value : h2Values) {
+          if (h1Val.equals(h2Value.getName())) {
+            found = true;
+            break;
+          }
+        }
+        if (!found) {
+          return false;
+        }
+      }
+      return true;
+    } else {
+      return false;
+    }
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/Handler.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/Handler.java
new file mode 100644
index 0000000..3801d33
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/Handler.java
@@ -0,0 +1,84 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+package jakarta.ws.rs.tck.common.webclient.handler;
+
+import org.apache.commons.httpclient.Header;
+
+/**
+ * Handler interface.
+ */
+public interface Handler {
+
+  /*
+   * public methods
+   * ========================================================================
+   */
+
+  /**
+   * Invokes handler logic.
+   * 
+   * @param configuredHeader
+   *          the user configured header
+   * @param responseHeader
+   *          the response header from the server
+   * @return True if the passed match, otherwise false
+   */
+  public boolean invoke(Header configuredHeader, Header responseHeader);
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/HandlerFactory.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/HandlerFactory.java
new file mode 100644
index 0000000..6d90810
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/HandlerFactory.java
@@ -0,0 +1,126 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package jakarta.ws.rs.tck.common.webclient.handler;
+
+/**
+ * <PRE>
+ * The HandlerManager is responsible for returning the appropriate handler
+ * instance based on the provided value.
+ */
+public class HandlerFactory {
+
+  /**
+   * Content-Type handler name.
+   */
+  private static final String CONTENT_TYPE = "content-type";
+
+  /**
+   * Location handler name.
+   */
+  private static final String LOCATION = "location";
+
+  /**
+   * Set-Cookie handler name.
+   */
+  private static final String SET_COOKIE = "set-cookie";
+
+  /**
+   * ALLOW handler name.
+   */
+  private static final String ALLOW = "allow";
+
+  /**
+   * www-authenticate handler name.
+   */
+  private static final String WWW_AUTH = "www-authenticate";
+  /*
+   * public methods
+   * ========================================================================
+   */
+
+  /**
+   * Constructs a new HandlerManager instance
+   */
+  private HandlerFactory() {
+  }
+
+  /**
+   * Returns the appropriate handler instance based on provided discriminate (a
+   * header name).
+   *
+   * @param handlerName
+   *          handler instance to obtain.
+   */
+  public static Handler getHandler(String handlerName) {
+    if (CONTENT_TYPE.equals(handlerName.toLowerCase())) {
+      return ContentTypeHandler.getInstance();
+    } else if (LOCATION.equals(handlerName.toLowerCase())) {
+      return LocationHandler.getInstance();
+    } else if (SET_COOKIE.equals(handlerName.toLowerCase())) {
+      return SetCookieHandler.getInstance();
+    } else if (WWW_AUTH.equals(handlerName.toLowerCase())) {
+      return WWWAuthenticateHandler.getInstance();
+    } else if (ALLOW.equals(handlerName.toLowerCase())) {
+      return ALLOWHandler.getInstance();
+    } else {
+      return DefaultHandler.getInstance();
+    }
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/LocationHandler.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/LocationHandler.java
new file mode 100644
index 0000000..835bb73
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/LocationHandler.java
@@ -0,0 +1,162 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000 The Apache Software Foundation.  All rights
+ * Copyright (c) 2000 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package jakarta.ws.rs.tck.common.webclient.handler;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.commons.httpclient.Header;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+
+/**
+ * <PRE>
+ * Will handle headers for the following
+ * cases:
+ *   - Server is on port 80 and port value isn't
+ *     propagated back to client (assumed)
+ *   - Port value is in response
+ * </PRE>
+ */
+public class LocationHandler implements Handler {
+
+  private static Handler handler = new LocationHandler();
+
+  /**
+   * Creates new ContentTypeHandler
+   */
+  private LocationHandler() {
+  }
+
+  /*
+   * public methods
+   * ========================================================================
+   */
+
+  /**
+   * Returns an instance of this handler.
+   */
+  public static Handler getInstance() {
+    return handler;
+  }
+
+  /**
+   * Invokes handler logic.
+   * 
+   * @param configuredHeader
+   *          the user configured header
+   * @param responseHeader
+   *          the response header from the server
+   * @return True if the passed match, otherwise false
+   */
+  public boolean invoke(Header configuredHeader, Header responseHeader) {
+
+    boolean pass = true;
+
+    try {
+      TestUtil.logTrace("[LocationHandler] LocationHandler invoked.");
+
+      URL configURL = new URL(configuredHeader.getValue());
+      URL responseURL = new URL(responseHeader.getValue());
+
+      if (!(configURL.getProtocol().equals(responseURL.getProtocol()))) {
+        pass = false;
+        TestUtil.logErr("[LocationHandler] Mismatch between protocols:");
+        TestUtil.logErr(
+            "[LocationHandler] Configured value: " + configURL.getProtocol());
+        TestUtil.logErr(
+            "[LocationHandler] Response value: " + responseURL.getProtocol());
+      }
+
+      if (!(configURL.getPath().equals(responseURL.getPath()))) {
+        pass = false;
+        TestUtil.logErr("[LocationHandler] Mismatch between paths:");
+        TestUtil.logErr(
+            "[LocationHandler] Configured value: " + configURL.getPath());
+        TestUtil.logErr(
+            "[LocationHandler] Response value: " + responseURL.getPath());
+      }
+
+      if (configURL.getQuery() == null) {
+        if (responseURL.getQuery() != null) {
+          pass = false;
+          TestUtil.logErr("[LocationHandler] Mismatch between querys:");
+          TestUtil.logErr("[LocationHandler] Configured value is null");
+          TestUtil.logErr("[LocationHandler] Response value is non-null");
+        }
+      } else if (!(configURL.getQuery().equals(responseURL.getQuery()))) {
+        pass = false;
+        TestUtil.logErr("[LocationHandler] Mismatch between querys:");
+        TestUtil.logErr(
+            "[LocationHandler] Configured value: " + configURL.getQuery());
+        TestUtil.logErr(
+            "[LocationHandler] Response value: " + responseURL.getQuery());
+      }
+
+    } catch (MalformedURLException mue) {
+      pass = false;
+      TestUtil.logErr("[LocationHandler] MalformedURLException");
+      TestUtil.printStackTrace(mue);
+    }
+
+    return pass;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/SetCookieHandler.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/SetCookieHandler.java
new file mode 100644
index 0000000..bb3b3ec
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/SetCookieHandler.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.common.webclient.handler;
+
+import java.util.StringTokenizer;
+
+import org.apache.commons.httpclient.Header;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+
+public class SetCookieHandler implements Handler {
+
+  private static final Handler HANDLER = new SetCookieHandler();
+
+  private static final String DELIM = "##";
+
+  private SetCookieHandler() {
+  }
+
+  public static Handler getInstance() {
+    return HANDLER;
+  }
+
+  public boolean invoke(Header configuredHeader, Header responseHeader) {
+    String setCookieHeader = responseHeader.getValue().toLowerCase();
+    String expectedValues = configuredHeader.getValue().toLowerCase();
+
+    TestUtil.logTrace(
+        "[SetCookieHandler] Set-Cookie header received: " + setCookieHeader);
+
+    StringTokenizer conf = new StringTokenizer(expectedValues, DELIM);
+    while (conf.hasMoreTokens()) {
+      String token = conf.nextToken();
+      String token1 = token;
+
+      if (token.endsWith("\"") && (token.indexOf("=\"") > 1)) {
+        token1 = token.replace("=\"", "=");
+        token1 = token1.substring(0, token.length() - 2);
+      }
+
+      if (token.startsWith("!")) {
+        String attr = token.substring(1);
+        String attr1 = token1.substring(1);
+        if ((setCookieHeader.indexOf(attr) > -1)
+            || (setCookieHeader.indexOf(attr1) > -1)) {
+          TestUtil.logErr("[SetCookieHandler] Unexpected attribute found "
+              + " Set-Cookie header.  Attribute: " + attr
+              + "\nSet-Cookie header: " + setCookieHeader);
+          return false;
+        }
+      } else {
+        if ((setCookieHeader.indexOf(token) < 0)
+            && (setCookieHeader.indexOf(token1) < 0)) {
+          TestUtil.logErr("[SetCookieHandler] Unable to find '" + token
+              + "' within the Set-Cookie header returned by the server.");
+          return false;
+        } else {
+          TestUtil.logTrace("[SetCookieHandler] Found expected value, '" + token
+              + "' in Set-Cookie header returned by server.");
+        }
+      }
+    }
+
+    return true;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/WWWAuthenticateHandler.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/WWWAuthenticateHandler.java
new file mode 100644
index 0000000..898df21
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/handler/WWWAuthenticateHandler.java
@@ -0,0 +1,113 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000 The Apache Software Foundation.  All rights
+ * Copyright (c) 2000 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package jakarta.ws.rs.tck.common.webclient.handler;
+
+import org.apache.commons.httpclient.Header;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+
+/**
+ * <PRE>
+ * Will handle headers for the following
+ * cases:
+ *   - Server is on port 80 and port value isn't
+ *     propagated back to client (assumed)
+ *   - Port value is in response
+ * </PRE>
+ */
+public class WWWAuthenticateHandler implements Handler {
+
+  private static Handler handler = new WWWAuthenticateHandler();
+
+  /**
+   * Creates new ContentTypeHandler
+   */
+  private WWWAuthenticateHandler() {
+  }
+
+  /*
+   * public methods
+   * ========================================================================
+   */
+
+  /**
+   * Returns an instance of this handler.
+   */
+  public static Handler getInstance() {
+    return handler;
+  }
+
+  /**
+   * Invokes handler logic.
+   * 
+   * @param configuredHeader
+   *          the user configured header
+   * @param responseHeader
+   *          the response header from the server
+   * @return True if the passed match, otherwise false
+   */
+  public boolean invoke(Header configuredHeader, Header responseHeader) {
+
+    TestUtil
+        .logTrace("[WWWAuthenticateHandler] WWAuthenticateHandler invoked.");
+    return true;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/http/HttpRequest.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/http/HttpRequest.java
new file mode 100644
index 0000000..a1aa017
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/http/HttpRequest.java
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.common.webclient.http;
+
+import java.io.IOException;
+import java.util.StringTokenizer;
+
+import org.apache.commons.httpclient.Cookie;
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpConnection;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.HttpState;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthScope;
+import org.apache.commons.httpclient.cookie.CookiePolicy;
+import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
+import org.apache.commons.httpclient.methods.StringRequestEntity;
+import org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory;
+import org.apache.commons.httpclient.protocol.Protocol;
+import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
+import org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+import jakarta.ws.rs.tck.common.webclient.Util;
+
+/**
+ * Represents an HTTP client Request
+ */
+
+public class HttpRequest {
+
+  static {
+    // if (TestUtil.traceflag) {
+    //   System.setProperty("org.apache.commons.logging.Log",
+    //       "jakarta.ws.rs.tck.common.webclient.log.WebLog");
+    //   System.setProperty(
+    //       "org.apache.commons.logging.simplelog.log.httpclient.wire", "debug");
+    // }
+  }
+
+  /**
+   * Default HTTP port.
+   */
+  public static int DEFAULT_HTTP_PORT = 80;
+
+  /**
+   * Default HTTP SSL port.
+   */
+  public static final int DEFAULT_SSL_PORT = 443;
+
+  /**
+   * No authentication
+   */
+  public static final int NO_AUTHENTICATION = 0;
+
+  /**
+   * Basic authentication
+   */
+  public static final int BASIC_AUTHENTICATION = 1;
+
+  /**
+   * Digest authenctication
+   */
+  public static final int DIGEST_AUTHENTICATION = 2;
+
+  /**
+   * Method representation of request.
+   */
+  private HttpMethod _method = null;
+
+  /**
+   * Target web container host
+   */
+  private String _host = null;
+
+  /**
+   * Target web container port
+   */
+  private int _port = DEFAULT_HTTP_PORT;
+
+  /**
+   * Is the request going over SSL
+   */
+  private boolean _isSecure = false;
+
+  /**
+   * HTTP state
+   */
+  private HttpState _state = null;
+
+  /**
+   * Original request line for this request.
+   */
+  private String _requestLine = null;
+
+  /**
+   * Authentication type for current request
+   */
+  private int _authType = NO_AUTHENTICATION;
+
+  /**
+   * Flag to determine if session tracking will be used or not.
+   */
+  private boolean _useCookies = false;
+
+  /**
+   * Content length of request body.
+   */
+  private int _contentLength = 0;
+
+  /**
+   * FollowRedirects
+   */
+  private boolean _redirect = false;
+
+  Header[] _headers = null;
+
+  protected HttpClient client = null;
+
+  /**
+   * Creates new HttpRequest based of the passed request line. The request line
+   * provied must be in the form of:<br>
+   * 
+   * <pre>
+   *     METHOD PATH HTTP-VERSION
+   *     Ex.  GET /index.html HTTP/1.0
+   * </pre>
+   */
+  public HttpRequest(String requestLine, String host, int port) {
+    client = new HttpClient();
+    _method = MethodFactory.getInstance(requestLine);
+    _method.setFollowRedirects(false);
+    _host = host;
+    _port = port;
+
+    if (port == DEFAULT_SSL_PORT) {
+      _isSecure = true;
+    }
+
+    // If we got this far, the request line is in the proper
+    // format
+    _requestLine = requestLine;
+  }
+
+  /*
+   * public methods
+   * ========================================================================
+   */
+
+  /**
+   * <code>getRequestPath</code> returns the request path for this particular
+   * request.
+   *
+   * @return String request path
+   */
+  public String getRequestPath() {
+    return _method.getPath();
+  }
+
+  /**
+   * <code>getRequestMethod</code> returns the request type, i.e., GET, POST,
+   * etc.
+   *
+   * @return String request type
+   */
+  public String getRequestMethod() {
+    return _method.getName();
+  }
+
+  /**
+   * <code>isSecureConnection()</code> indicates if the Request is secure or
+   * not.
+   *
+   * @return boolean whether Request is using SSL or not.
+   */
+  public boolean isSecureRequest() {
+    return _isSecure;
+  }
+
+  /**
+   * <code>setSecureRequest</code> configures this request to use SSL.
+   *
+   * @param secure
+   *          - whether the Request uses SSL or not.
+   */
+  public void setSecureRequest(boolean secure) {
+    _isSecure = secure;
+  }
+
+  /**
+   * <code>setContent</code> will set the body for this request. Note, this is
+   * only valid for POST and PUT operations, however, if called and the request
+   * represents some other HTTP method, it will be no-op'd.
+   *
+   * @param content
+   *          request content
+   */
+  public void setContent(String content) {
+    if (_method instanceof EntityEnclosingMethod) {
+      ((EntityEnclosingMethod) _method)
+          .setRequestEntity(new StringRequestEntity(content));
+    }
+    _contentLength = content.length();
+  }
+
+  /**
+   * <code>setAuthenticationCredentials configures the request to
+   * perform authentication.
+   *
+   * <p><code>username</code> and <code>password</code> cannot be null.
+   * </p>
+   *
+   * <p>
+   * It is legal for <code>realm</code> to be null.
+   * </p>
+   *
+   * @param username
+   *          the user
+   * @param password
+   *          the user's password
+   * @param authType
+   *          authentication type
+   * @param realm
+   *          authentication realm
+   */
+  public void setAuthenticationCredentials(String username, String password,
+      int authType, String realm) {
+    if (username == null) {
+      throw new IllegalArgumentException("Username cannot be null");
+    }
+
+    if (password == null) {
+      throw new IllegalArgumentException("Password cannot be null");
+    }
+
+    UsernamePasswordCredentials cred = new UsernamePasswordCredentials(username,
+        password);
+    AuthScope scope = new AuthScope(_host, _port, realm);
+    getState().setCredentials(scope, cred);
+    TestUtil.logTrace("[HttpRequest] Added credentials for '" + username
+        + "' with password '" + password + "' in realm '" + realm + "'");
+
+    _authType = authType;
+  }
+
+  /**
+   * <code>addRequestHeader</code> adds a request header to this request. If a
+   * request header of the same name already exists, the new value, will be
+   * added to the set of already existing values.
+   *
+   * <strong>NOTE:</strong> that header names are not case-sensitive.
+   *
+   * @param headerName
+   *          request header name
+   * @param headerValue
+   *          request header value
+   */
+  public void addRequestHeader(String headerName, String headerValue) {
+    _method.addRequestHeader(headerName, headerValue);
+    TestUtil.logTrace("[HttpRequest] Added request header: "
+        + _method.getRequestHeader(headerName).toExternalForm());
+  }
+
+  public void addRequestHeader(String header) {
+    StringTokenizer st = new StringTokenizer(header, "|");
+    while (st.hasMoreTokens()) {
+      String h = st.nextToken();
+      if (h.toLowerCase().startsWith("cookie")) {
+        createCookie(h);
+        continue;
+      }
+      int col = h.indexOf(':');
+      addRequestHeader(h.substring(0, col).trim(), h.substring(col + 1).trim());
+    }
+  }
+
+  /**
+   * <code>setRequestHeader</code> sets a request header for this request
+   * overwritting any previously existing header/values with the same name.
+   *
+   * <strong>NOTE:</strong> Header names are not case-sensitive.
+   *
+   * @param headerName
+   *          request header name
+   * @param headerValue
+   *          request header value
+   */
+  public void setRequestHeader(String headerName, String headerValue) {
+    _method.setRequestHeader(headerName, headerValue);
+    TestUtil.logTrace("[HttpRequest] Set request header: "
+        + _method.getRequestHeader(headerName).toExternalForm());
+
+  }
+
+  /**
+   * <code>setFollowRedirects</code> indicates whether HTTP redirects are
+   * followed. By default, redirects are not followed.
+   */
+  public void setFollowRedirects(boolean followRedirects) {
+    _method.setFollowRedirects(followRedirects);
+  }
+
+  /**
+   * <code>getFollowRedirects</code> indicates whether HTTP redirects are
+   * followed.
+   */
+  public boolean getFollowRedirects() {
+    return _method.getFollowRedirects();
+  }
+
+  /**
+   * <code>setState</code> will set the HTTP state for the current request (i.e.
+   * session tracking). This has the side affect
+   */
+  public void setState(HttpState state) {
+    _state = state;
+    _useCookies = true;
+  }
+
+  /**
+   * <code>execute</code> will dispatch the current request to the target
+   * server.
+   *
+   * @return HttpResponse the server's response.
+   * @throws IOException
+   *           if an I/O error occurs during dispatch.
+   */
+  public HttpResponse execute() throws IOException, HttpException {
+    String method;
+    int defaultPort;
+    ProtocolSocketFactory factory;
+
+    if (_method.getFollowRedirects()) {
+      client = new HttpClient();
+
+      if (_isSecure) {
+        method = "https";
+        defaultPort = DEFAULT_SSL_PORT;
+        factory = new SSLProtocolSocketFactory();
+      } else {
+        method = "http";
+        defaultPort = DEFAULT_HTTP_PORT;
+        factory = new DefaultProtocolSocketFactory();
+      }
+
+      Protocol protocol = new Protocol(method, factory, defaultPort);
+      HttpConnection conn = new HttpConnection(_host, _port, protocol);
+
+      if (conn.isOpen()) {
+        throw new IllegalStateException("Connection incorrectly opened");
+      }
+
+      conn.open();
+
+      TestUtil.logMsg("[HttpRequest] Dispatching request: '" + _requestLine
+          + "' to target server at '" + _host + ":" + _port + "'");
+
+      addSupportHeaders();
+      _headers = _method.getRequestHeaders();
+
+      TestUtil.logTrace(
+          "########## The real value set: " + _method.getFollowRedirects());
+
+      client.getHostConfiguration().setHost(_host, _port, protocol);
+
+      client.executeMethod(_method);
+
+      return new HttpResponse(_host, _port, _isSecure, _method, getState());
+    } else {
+      if (_isSecure) {
+        method = "https";
+        defaultPort = DEFAULT_SSL_PORT;
+        factory = new SSLProtocolSocketFactory();
+      } else {
+        method = "http";
+        defaultPort = DEFAULT_HTTP_PORT;
+        factory = new DefaultProtocolSocketFactory();
+      }
+
+      Protocol protocol = new Protocol(method, factory, defaultPort);
+      HttpConnection conn = new HttpConnection(_host, _port, protocol);
+
+      if (conn.isOpen()) {
+        throw new IllegalStateException("Connection incorrectly opened");
+      }
+
+      conn.open();
+
+      TestUtil.logMsg("[HttpRequest] Dispatching request: '" + _requestLine
+          + "' to target server at '" + _host + ":" + _port + "'");
+
+      addSupportHeaders();
+      _headers = _method.getRequestHeaders();
+
+      TestUtil.logTrace(
+          "########## The real value set: " + _method.getFollowRedirects());
+
+      _method.execute(getState(), conn);
+
+      return new HttpResponse(_host, _port, _isSecure, _method, getState());
+    }
+  }
+
+  /**
+   * Returns the current state for this request.
+   *
+   * @return HttpState current state
+   */
+  public HttpState getState() {
+    if (_state == null) {
+      _state = new HttpState();
+    }
+    return _state;
+  }
+
+  public String toString() {
+    StringBuffer sb = new StringBuffer(255);
+    sb.append("[REQUEST LINE] -> ").append(_requestLine).append('\n');
+
+    if (_headers != null && _headers.length != 0) {
+
+      for (Header _header : _headers) {
+        sb.append("       [REQUEST HEADER] -> ");
+        sb.append(_header.toExternalForm()).append('\n');
+      }
+    }
+
+    if (_contentLength != 0) {
+      sb.append("       [REQUEST BODY LENGTH] -> ").append(_contentLength);
+      sb.append('\n');
+    }
+
+    return sb.toString();
+
+  }
+
+  /*
+   * private methods
+   * ========================================================================
+   */
+
+  private void createCookie(String cookieHeader) {
+    String cookieLine = cookieHeader.substring(cookieHeader.indexOf(':') + 1)
+        .trim();
+    StringTokenizer st = new StringTokenizer(cookieLine, " ;");
+    Cookie cookie = new Cookie();
+    cookie.setVersion(1);
+
+    getState();
+
+    if (cookieLine.indexOf("$Version") == -1) {
+      cookie.setVersion(0);
+      _method.getParams().setCookiePolicy(CookiePolicy.NETSCAPE);
+    }
+
+    while (st.hasMoreTokens()) {
+      String token = st.nextToken();
+
+      if (token.charAt(0) != '$' && !token.startsWith("Domain")
+          && !token.startsWith("Path")) {
+        cookie.setName(token.substring(0, token.indexOf('=')));
+        cookie.setValue(token.substring(token.indexOf('=') + 1));
+      } else if (token.indexOf("Domain") > -1) {
+        cookie.setDomainAttributeSpecified(true);
+        cookie.setDomain(token.substring(token.indexOf('=') + 1));
+      } else if (token.indexOf("Path") > -1) {
+        cookie.setPathAttributeSpecified(true);
+        cookie.setPath(token.substring(token.indexOf('=') + 1));
+      }
+    }
+    _state.addCookie(cookie);
+
+  }
+
+  /**
+   * Adds any support request headers necessary for this request. These headers
+   * will be added based on the state of the request.
+   */
+  private void addSupportHeaders() {
+
+    // Authentication headers
+    // NOTE: Possibly move logic to generic method
+    switch (_authType) {
+    case NO_AUTHENTICATION:
+      break;
+    case BASIC_AUTHENTICATION:
+      setBasicAuthorizationHeader();
+      break;
+    case DIGEST_AUTHENTICATION:
+      throw new UnsupportedOperationException(
+          "Digest Authentication is not currently " + "supported");
+    }
+
+    // A Host header will be added to each request to handle
+    // cases where virtual hosts are used, or there is no DNS
+    // available on the system where the container is running.
+    setHostHeader();
+
+    // Content length header
+    setContentLengthHeader();
+
+    // Cookies
+    setCookieHeader();
+  }
+
+  /**
+   * Sets a basic authentication header in the request is Request is configured
+   * to use basic authentication
+   */
+  private void setBasicAuthorizationHeader() {
+    UsernamePasswordCredentials cred = (UsernamePasswordCredentials) getState()
+        .getCredentials(new AuthScope(_host, _port, null));
+    String authString = null;
+    if (cred != null) {
+      authString = "Basic " + Util.getBase64EncodedString(
+          cred.getUserName() + ":" + cred.getPassword());
+    } else {
+      TestUtil.logTrace("[HttpRequest] NULL CREDENTIALS");
+    }
+    _method.setRequestHeader("Authorization", authString);
+  }
+
+  /**
+   * Sets a Content-Length header in the request if content is present
+   */
+  private void setContentLengthHeader() {
+    if (_contentLength > 0) {
+      _method.setRequestHeader("Content-Length",
+          Integer.toString(_contentLength));
+    }
+  }
+
+  /**
+   * Sets a host header in the request. If the configured host value is an IP
+   * address, the Host header will be sent, but without any value.
+   *
+   * If we adhered to the HTTP/1.1 spec, the Host header must be empty of the
+   * target server is identified via IP address. However, no user agents I've
+   * tested follow this. And if a custom client library does this, it may not
+   * work properly with the target server. For now, the Host request-header will
+   * always have a value.
+   */
+  private void setHostHeader() {
+    if (_port == DEFAULT_HTTP_PORT || _port == DEFAULT_SSL_PORT) {
+      _method.setRequestHeader("Host", _host);
+    } else {
+      _method.setRequestHeader("Host", _host + ":" + _port);
+    }
+  }
+
+  /**
+   * Sets a Cookie header if this request is using cookies.
+   */
+  private void setCookieHeader() {
+    if (_useCookies) {
+      Cookie[] cookies = _state.getCookies();
+      if (cookies != null && cookies.length > 0) {
+        Header cHeader = CookiePolicy.getCookieSpec(CookiePolicy.RFC_2109)
+            .formatCookieHeader(_state.getCookies());
+        if (cHeader != null) {
+          _method.setRequestHeader(cHeader);
+        }
+      }
+    }
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/http/HttpResponse.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/http/HttpResponse.java
new file mode 100644
index 0000000..177d6df
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/http/HttpResponse.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2006, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.common.webclient.http;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.HttpMethodBase;
+import org.apache.commons.httpclient.HttpState;
+import org.apache.commons.httpclient.HttpVersion;
+
+import jakarta.ws.rs.tck.common.webclient.Util;
+
+/**
+ * This class represents an HTTP response from the server.
+ */
+
+public class HttpResponse {
+
+  /**
+   * Default encoding based on Servlet Specification
+   */
+  private static final String DEFAULT_ENCODING = "ISO-8859-1";
+
+  /**
+   * Content-Type header
+   */
+  private static final String CONTENT_TYPE = "Content-Type";
+
+  /**
+   * Wrapped HttpMethod used to pull response info from.
+   */
+  private HttpMethod _method = null;
+
+  /**
+   * HttpState obtained after execution of request
+   */
+  private HttpState _state = null;
+
+  /**
+   * Charset encoding returned in the response
+   */
+  private String _encoding = DEFAULT_ENCODING;
+
+  /**
+   * The response body. Initialized after first call to one of the
+   * getResponseBody methods and cached for subsequent calls.
+   */
+  private String _responseBody = null;
+
+  /**
+   * Host name used for processing request
+   */
+  private String _host = null;
+
+  /**
+   * Port number used for processing request
+   */
+  private int _port;
+
+  /**
+   * Issecure
+   */
+  private boolean _isSecure;
+
+  /** Creates new HttpResponse */
+  public HttpResponse(String host, int port, boolean isSecure,
+      HttpMethod method, HttpState state) {
+
+    _host = host;
+    _port = port;
+    _isSecure = isSecure;
+    _method = method;
+    _state = state;
+  }
+
+  /*
+   * public methods
+   * ========================================================================
+   */
+
+  /**
+   * Returns the HTTP status code returned by the server
+   *
+   * @return HTTP status code
+   */
+  public String getStatusCode() {
+    return Integer.toString(_method.getStatusCode());
+  }
+
+  /**
+   * Returns the HTTP reason-phrase returned by the server
+   *
+   * @return HTTP reason-phrase
+   */
+  public String getReasonPhrase() {
+    return _method.getStatusText();
+  }
+
+  /**
+   * Returns the headers received in the response from the server.
+   *
+   * @return response headers
+   */
+  public Header[] getResponseHeaders() {
+    return _method.getResponseHeaders();
+  }
+
+  /**
+   * Returns the headers designated by the name provided.
+   *
+   * @return response headers
+   */
+  public Header[] getResponseHeaders(String headerName) {
+    return _method.getResponseHeaders(headerName);
+  }
+
+  /**
+   * Returns the response header designated by the name provided.
+   *
+   * @return a specfic response header or null if the specified header doesn't
+   *         exist.
+   */
+  public Header getResponseHeader(String headerName) {
+    return _method.getResponseHeader(headerName);
+  }
+
+  /**
+   * Returns the response body as a byte array using the charset specified in
+   * the server's response.
+   *
+   * @return response body as an array of bytes.
+   */
+  public byte[] getResponseBodyAsBytes() throws IOException {
+    return getEncodedResponse().getBytes();
+  }
+
+  /**
+   * Returns the response as bytes (no encoding is performed by client.
+   * 
+   * @return the raw response bytes
+   * @throws IOException
+   *           if an error occurs reading from server
+   */
+  public byte[] getResponseBodyAsRawBytes() throws IOException {
+    return _method.getResponseBody();
+  }
+
+  /**
+   * Returns the response body as a string using the charset specified in the
+   * server's response.
+   *
+   * @return response body as a String
+   */
+  public String getResponseBodyAsString() throws IOException {
+    return getEncodedResponse();
+  }
+
+  /**
+   * Returns the response body of the server without being encoding by the
+   * client.
+   * 
+   * @return an unecoded String representation of the response
+   * @throws IOException
+   *           if an error occurs reading from the server
+   */
+  public String getResponseBodyAsRawString() throws IOException {
+    return _method.getResponseBodyAsString();
+  }
+
+  /**
+   * Returns the response body as an InputStream using the encoding specified in
+   * the server's response.
+   *
+   * @return response body as an InputStream
+   */
+  public InputStream getResponseBodyAsStream() throws IOException {
+    return new ByteArrayInputStream(getEncodedResponse().getBytes());
+  }
+
+  /**
+   * Returns the response body as an InputStream without any encoding applied by
+   * the client.
+   * 
+   * @return an InputStream to read the response
+   * @throws IOException
+   *           if an error occurs reading from the server
+   */
+  public InputStream getResponseBodyAsRawStream() throws IOException {
+    return _method.getResponseBodyAsStream();
+  }
+
+  /**
+   * Returns the charset encoding for this response.
+   *
+   * @return charset encoding
+   */
+  public String getResponseEncoding() {
+    Header content = _method.getResponseHeader(CONTENT_TYPE);
+    if (content != null) {
+      String headerVal = content.getValue();
+      int idx = headerVal.indexOf(";charset=");
+      if (idx > -1) {
+        // content encoding included in response
+        _encoding = headerVal.substring(idx + 9);
+      }
+    }
+    return _encoding;
+  }
+
+  /**
+   * Returns the post-request state.
+   *
+   * @return an HttpState object
+   */
+  public HttpState getState() {
+    return _state;
+  }
+
+  /**
+   * Displays a String representation of the response.
+   *
+   * @return string representation of response
+   */
+  public String toString() {
+    StringBuffer sb = new StringBuffer(255);
+
+    sb.append("[RESPONSE STATUS LINE] -> ");
+    sb.append(((HttpMethodBase) _method).getParams().getVersion()
+        .equals(HttpVersion.HTTP_1_1) ? "HTTP/1.1 " : "HTTP/1.0 ");
+    sb.append(_method.getStatusCode()).append(' ');
+    sb.append(_method.getStatusText()).append('\n');
+    Header[] headers = _method.getResponseHeaders();
+    if (headers != null && headers.length != 0) {
+      for (int i = 0; i < headers.length; i++) {
+        sb.append("       [RESPONSE HEADER] -> ");
+        sb.append(headers[i].toExternalForm()).append('\n');
+      }
+    }
+
+    String resBody;
+    try {
+      resBody = _method.getResponseBodyAsString();
+    } catch (IOException ioe) {
+      resBody = "UNEXECTED EXCEPTION: " + ioe.toString();
+    }
+    if (resBody != null && resBody.length() != 0) {
+      sb.append("------ [RESPONSE BODY] ------\n");
+      sb.append(resBody);
+      sb.append("\n-----------------------------\n\n");
+    }
+    return sb.toString();
+  }
+
+  /*
+   * Eventually they need to come from _method
+   */
+
+  public String getHost() {
+    return _host;
+  }
+
+  public int getPort() {
+    return _port;
+  }
+
+  public String getProtocol() {
+    return _isSecure ? "https" : "http";
+  }
+
+  public String getPath() {
+    return _method.getPath();
+  }
+
+  /*
+   * Private Methods
+   * ==========================================================================
+   */
+
+  /**
+   * Returns the response body using the encoding returned in the response.
+   *
+   * @return encoded response String.
+   */
+  private String getEncodedResponse() throws IOException {
+    if (_responseBody == null) {
+      _responseBody = Util.getEncodedStringFromStream(
+          _method.getResponseBodyAsStream(), getResponseEncoding());
+    }
+    return _responseBody;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/http/MethodFactory.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/http/MethodFactory.java
new file mode 100644
index 0000000..0a03141
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/http/MethodFactory.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.common.webclient.http;
+
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.HttpMethodBase;
+import org.apache.commons.httpclient.HttpVersion;
+import org.apache.commons.httpclient.methods.DeleteMethod;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.HeadMethod;
+import org.apache.commons.httpclient.methods.OptionsMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.PutMethod;
+
+import jakarta.ws.rs.tck.lib.porting.TSURL;
+
+/**
+ * Simple factory class which returns HttpMethod implementations based on a
+ * request line.
+ * <p>
+ * For example, a request line of <tt>GET /index.jsp HTTP/1.0</tt> would return
+ * an HttpMethod implementation that handles GET requests using HTTP/1.0.
+ * </p>
+ */
+
+public class MethodFactory {
+
+  /**
+   * HTTP GET
+   */
+  private static final String GET_METHOD = "GET";
+
+  /**
+   * HTTP POST
+   */
+  private static final String POST_METHOD = "POST";
+
+  /**
+   * HTTP HEAD
+   */
+  private static final String HEAD_METHOD = "HEAD";
+
+  /**
+   * HTTP PUT
+   */
+  private static final String PUT_METHOD = "PUT";
+
+  /**
+   * HTTP DELETE
+   */
+  private static final String DELETE_METHOD = "DELETE";
+
+  /**
+   * HTTP OPTIONS
+   */
+  private static final String OPTIONS_METHOD = "OPTIONS";
+
+  /**
+   * TSURL implementation
+   */
+  private static final TSURL TS_URL = new TSURL();
+
+  /**
+   * Private constructor as all interaction with this class is through the
+   * getInstance() method.
+   */
+  private MethodFactory() {
+  }
+
+  /*
+   * public methods
+   * ========================================================================
+   */
+
+  /**
+   * Returns the approriate request method based on the provided request string.
+   * The request must be in the format of METHOD URI_PATH HTTP_VERSION, i.e. GET
+   * /index.jsp HTTP/1.1.
+   *
+   * @return HttpMethod based in request.
+   */
+  public static HttpMethod getInstance(String request) {
+    StringTokenizer st = new StringTokenizer(request);
+    String method;
+    String query = null;
+    String uri;
+    String version;
+    try {
+      method = st.nextToken();
+      uri = TS_URL.getRequest(st.nextToken());
+      version = st.nextToken();
+    } catch (NoSuchElementException nsee) {
+      throw new IllegalArgumentException(
+          "Request provided: " + request + " is malformed.");
+    }
+
+    // check to see if there is a query string appended
+    // to the URI
+    int queryStart = uri.indexOf('?');
+    if (queryStart != -1) {
+      query = uri.substring(queryStart + 1);
+      uri = uri.substring(0, queryStart);
+    }
+
+    HttpMethodBase req;
+
+    if (method.equals(GET_METHOD)) {
+      req = new GetMethod(uri);
+    } else if (method.equals(POST_METHOD)) {
+      req = new PostMethod(uri);
+    } else if (method.equals(PUT_METHOD)) {
+      req = new PutMethod(uri);
+    } else if (method.equals(DELETE_METHOD)) {
+      req = new DeleteMethod(uri);
+    } else if (method.equals(HEAD_METHOD)) {
+      req = new HeadMethod(uri);
+    } else if (method.equals(OPTIONS_METHOD)) {
+      req = new OptionsMethod(uri);
+    } else {
+      throw new IllegalArgumentException("Invalid method: " + method);
+    }
+
+    setHttpVersion(version, req);
+
+    if (query != null) {
+      req.setQueryString(query);
+    }
+
+    return req;
+  }
+
+  /*
+   * private methods
+   * ========================================================================
+   */
+
+  /**
+   * Sets the HTTP version for the method in question.
+   *
+   * @param version
+   *          HTTP version to use for this request
+   * @param method
+   *          method to adjust HTTP version
+   */
+  private static void setHttpVersion(String version, HttpMethodBase method) {
+    final String oneOne = "HTTP/1.1";
+    method.getParams().setVersion(
+        (version.equals(oneOne) ? HttpVersion.HTTP_1_1 : HttpVersion.HTTP_1_0));
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/validation/CheckOneOfStatusesTokenizedValidator.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/validation/CheckOneOfStatusesTokenizedValidator.java
new file mode 100644
index 0000000..654f181
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/validation/CheckOneOfStatusesTokenizedValidator.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.common.webclient.validation;
+
+import java.io.IOException;
+
+/**
+ * Sometimes it is not clear what result one should get, there might be more two
+ * or more possibilities. This strategy checks the response contains at least
+ * one of the given statuses.
+ * 
+ * The statuses are supposed to be separated by "|" character
+ * 
+ * @author Jan Supol
+ */
+public class CheckOneOfStatusesTokenizedValidator extends TokenizedValidator {
+
+  /**
+   * When WebTestCase contains more expected response codes it always means to
+   * check one of them is present; if present, other statuses are dropped. Super
+   * class method is called to get the logging messages
+   */
+  @Override
+  protected boolean checkStatusCode() throws IOException {
+    String responseCode = _res.getStatusCode();
+    String caseCodes = _case.getStatusCode();
+
+    if (caseCodes != null && caseCodes.charAt(0) != '!'
+        && caseCodes.contains("|") && caseCodes.contains(responseCode))
+      _case.setExpectedStatusCode(responseCode);
+    return super.checkStatusCode();
+  }
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/validation/TokenizedValidator.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/validation/TokenizedValidator.java
new file mode 100644
index 0000000..0237136
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/validation/TokenizedValidator.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.common.webclient.validation;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.StringTokenizer;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+import jakarta.ws.rs.tck.common.webclient.Goldenfile;
+
+/**
+ * <pre>
+ * This class provides all of the functionality of the
+ * WebValidatorBase class.  Additionally, it will compare
+ * the server's response body with the test case's configured
+ * goldenfile using a StringTokenizer.
+ * </pre>
+ */
+public class TokenizedValidator extends WebValidatorBase {
+
+  /**
+   * System property that will cause the specified goldenfile to be written if
+   * it doesn't already exist.
+   */
+  private static final String RECORD_GF = "ts.record.gf";
+
+  /**
+   * Creates a new instance of TokenizedValidator
+   */
+  public TokenizedValidator() {
+  }
+
+  /*
+   * protected methods
+   * ========================================================================
+   */
+
+  /**
+   * Compare the server response and golenfile using a StringTokenizer.
+   *
+   * @return true if response and goldenfile are the same.
+   * @throws IOException
+   *           if an error occurs will processing the Goldenfile
+   */
+  protected boolean checkGoldenfile() throws IOException {
+    String gf;
+    String path = _case.getGoldenfilePath();
+    String enc = _res.getResponseEncoding();
+
+    if (path == null) {
+      return true;
+    }
+
+    Goldenfile file = new Goldenfile(_case.getGoldenfilePath(), enc);
+
+    try {
+      gf = file.getGoldenFileAsString();
+    } catch (IOException ioe) {
+      TestUtil
+          .logErr("[TokenizedValidator] Unexpected exception while accessing "
+              + "goldenfile! " + ioe.toString());
+      return false;
+    }
+
+    String response = _res.getResponseBodyAsString();
+    StringTokenizer gfTokenizer = new StringTokenizer(gf);
+    StringTokenizer resTokenizer = new StringTokenizer(response);
+    int gfCount = gfTokenizer.countTokens();
+    int resCount = resTokenizer.countTokens();
+
+    // Logic to handle the recording of goldenfiles.
+    if (gf.equals("NO GOLDENFILE FOUND") && Boolean.getBoolean(RECORD_GF)) {
+
+      TestUtil
+          .logTrace("[TokenizedValidator][INFO] RECORDING GOLDENFILE: " + path);
+      OutputStreamWriter out = new OutputStreamWriter(
+          new FileOutputStream(path), enc);
+      out.write(response);
+      out.flush();
+      out.close();
+    }
+
+    // If the token counts are the same, continue checking
+    // each individual token, otherwise, immediately fail.
+    if (gfCount == resCount) {
+      while (gfTokenizer.hasMoreTokens()) {
+        String exp = gfTokenizer.nextToken();
+        String res = resTokenizer.nextToken();
+        if (!exp.equals(res)) {
+          StringBuffer sb = new StringBuffer(255);
+          sb.append("[TokenizedValidator]: Server's response and ");
+          sb.append("goldenfile to not match!\n");
+          sb.append("\n            Goldenfile token: ").append(exp);
+          sb.append("\n            Response token:   ").append(res);
+          TestUtil.logErr(sb.toString());
+          dumpResponseInfo(response, gf);
+          return false;
+        }
+      }
+    } else {
+      TestUtil
+          .logErr("[TokenizedValidator]: Token count between server response "
+              + "and goldenfile do not match.\n Response Token" + "count: "
+              + resCount + "\nGoldenfile Token count: " + gfCount);
+
+      dumpResponseInfo(response, gf);
+      return false;
+    }
+    TestUtil.logTrace("[TokenizedValidator]: Server's response matches the "
+        + "configured goldenfile.");
+    return true;
+  }
+
+  /*
+   * private methods
+   * ========================================================================
+   */
+
+  /**
+   * Dumps the response from the server and the content of the Goldenfile/
+   * 
+   * @param serverResponse
+   *          the response body from the server.
+   * @param goldenFile
+   *          the test goldenfile
+   */
+  private static void dumpResponseInfo(String serverResponse,
+      String goldenFile) {
+    StringBuffer sb = new StringBuffer(255);
+    sb.append("\nServer Response (below):\n");
+    sb.append("------------------------------------------\n");
+    sb.append(serverResponse);
+    sb.append("\n------------------------------------------\n");
+    sb.append("\nGoldenfile (below):\n");
+    sb.append("------------------------------------------\n");
+    sb.append(goldenFile);
+    sb.append("\n------------------------------------------\n");
+    TestUtil.logErr(sb.toString());
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/validation/ValidationFactory.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/validation/ValidationFactory.java
new file mode 100644
index 0000000..5505d73
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/validation/ValidationFactory.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.common.webclient.validation;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+
+/**
+ * Returns a ValidationStrategy instance used to validate a response against a
+ * particular WebTestCase
+ *
+ * @author Ryan Lubke
+ * @version %I%
+ */
+public class ValidationFactory {
+
+  /**
+   * Private constructor as all interaction with the class is through the
+   * getInstance() method.
+   */
+  private ValidationFactory() {
+  }
+
+  /*
+   * public methods
+   * ========================================================================
+   */
+
+  /**
+   * Returns a ValidationStrategy instance based on the available factory types.
+   *
+   * @param validator
+   *          Validator instance to obtain
+   * @return a ValidationStrategy instance or null if the instance could not be
+   *         obtained.
+   */
+  public static ValidationStrategy getInstance(String validator) {
+    try {
+      Object o = Thread.currentThread().getContextClassLoader()
+          .loadClass(validator).newInstance();
+      if (o instanceof ValidationStrategy) {
+        return (ValidationStrategy) o;
+      }
+    } catch (Throwable t) {
+      TestUtil.logMsg("[ValidationFactory] Unable to obtain "
+          + "ValidationStrategy instance: " + validator);
+    }
+    return null;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/validation/ValidationStrategy.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/validation/ValidationStrategy.java
new file mode 100644
index 0000000..f8998d9
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/validation/ValidationStrategy.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.common.webclient.validation;
+
+import jakarta.ws.rs.tck.common.webclient.WebTestCase;
+
+/**
+ * A ValidationStrategy is used to compare a server response with a configured
+ * test case. How this validation is performed is up to the concrete
+ * implementation.
+ */
+public interface ValidationStrategy {
+  public boolean validate(WebTestCase testCase);
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/validation/WebValidatorBase.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/validation/WebValidatorBase.java
new file mode 100644
index 0000000..4a0d027
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/common/webclient/validation/WebValidatorBase.java
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.common.webclient.validation;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.httpclient.Header;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+import jakarta.ws.rs.tck.common.webclient.WebTestCase;
+import jakarta.ws.rs.tck.common.webclient.handler.Handler;
+import jakarta.ws.rs.tck.common.webclient.handler.HandlerFactory;
+import jakarta.ws.rs.tck.common.webclient.http.HttpRequest;
+import jakarta.ws.rs.tck.common.webclient.http.HttpResponse;
+
+/**
+ * Base abstract class for WebTestCase validation.
+ */
+public abstract class WebValidatorBase implements ValidationStrategy {
+
+  /**
+   * Used to detect 4xx class HTTP errors to allow fail fast situations when 4xx
+   * errors are not expected.
+   */
+  protected static final char CLIENT_ERROR = '4';
+
+  /**
+   * Used to detect 5xx class HTTP errors to allows fail fast situations when
+   * 5xx errors are not expected.
+   */
+  protected static final char SERVER_ERROR = '5';
+
+  /**
+   * This test case's HttpResponse
+   */
+  protected HttpResponse _res = null;
+
+  /**
+   * This test case's HttpRequest
+   */
+  protected HttpRequest _req = null;
+
+  /**
+   * The test case being validated
+   */
+  protected WebTestCase _case = null;
+
+  /**
+   * <tt>validate</tt> Will validate the response against the configured
+   * TestCase.
+   *
+   *
+   * <ul>
+   * <li>Check the HTTP status-code</li>
+   * <li>Check the HTTP reason-phrase</li>
+   * <li>Check for expected headers</li>
+   * <li>Check from unexpected headers</li>
+   * <li>Check expected search strings</li>
+   * <li>Check unexpected search strings</li>
+   * <li>Check the goldenfile</li>
+   * </ul>
+   */
+  public boolean validate(WebTestCase testCase) {
+    _res = testCase.getResponse();
+    _req = testCase.getRequest();
+    _case = testCase;
+
+    // begin the check
+    try {
+      if (!checkStatusCode() || !checkReasonPhrase() || !checkExpectedHeaders()
+          || !checkUnexpectedHeaders() || !checkSearchStrings()
+          || !checkSearchStringsNoCase() || !checkUnorderedSearchStrings()
+          || !checkUnexpectedSearchStrings() || !checkGoldenfile()) {
+        return false;
+      }
+    } catch (IOException ioe) {
+      TestUtil
+          .logErr("[WebValidatorBase] Unexpected Exception: " + ioe.toString());
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * <code>checkStatusCode</code> will perform status code comparisons based on
+   * the algorithm below
+   * <ul>
+   * <li>Check the HTTP status code</li>
+   * <ul>
+   * <li>
+   * <p>
+   * If status code is -1, then return true
+   * </p>
+   * </li>
+   * <li>
+   * <p>
+   * If test case status code null and response 4xx, return failure, print
+   * error; return false
+   * </p>
+   * </li>
+   * <li>
+   * <p>
+   * If test case status code null and response 5xx, return failure include
+   * response body; return false
+   * <p>
+   * </li>
+   * <li>
+   * <p>
+   * If test case status code null, and response not 4xx or 5xx, return true
+   * </p>
+   * </li>
+   * <li>
+   * <p>
+   * Test case status code not null, compare it with the response status code;
+   * return true if equal
+   * <p>
+   * <li>
+   * </ul>
+   * </ul>
+   *
+   * @return boolen result of check
+   * @throws IOException
+   *           if an IO error occurs during validation
+   */
+  protected boolean checkStatusCode() throws IOException {
+    String sCode = _case.getStatusCode();
+    String resCode = _res.getStatusCode();
+    if ("-1".equals(sCode))
+      return true;
+
+    if (sCode == null && resCode.charAt(0) == CLIENT_ERROR) {
+      TestUtil
+          .logErr("[WebValidatorBase] Unexpected " + resCode + " received from "
+              + "target server!  Request path: " + _req.getRequestPath());
+      return false;
+    }
+
+    if (sCode == null && (resCode.charAt(0) == SERVER_ERROR)) {
+      String resBody = _res.getResponseBodyAsRawString();
+      StringBuffer sb = new StringBuffer(75 + resBody.length());
+      sb.append("[WebValidatorBase] Unexpected '");
+      sb.append(resCode).append("' received from target server!\n");
+      sb.append("Error response recieved from server:\n");
+      sb.append("------------------------------------------------\n");
+      sb.append(resBody != null ? resBody : "NO RESPONSE");
+      TestUtil.logErr(sb.toString());
+      return false;
+    }
+
+    if (sCode == null) {
+      return true;
+    }
+
+    // test status code not null, compare with that of the response
+    if (sCode.charAt(0) != '!') {
+      if (!sCode.equals(resCode)) {
+        TestUtil.logErr("[WebValidatorBase] Unexpected Status Code "
+            + "recieved from server.  Expected '" + sCode + "' received '"
+            + resCode + "'");
+        return false;
+      }
+
+      TestUtil.logTrace("[WebValidatorBase] Expected Status Code '" + sCode
+          + "' found in response line!");
+    } else {
+      sCode = sCode.substring(1);
+      if (sCode.equals(resCode)) {
+        TestUtil.logErr("[WebValidatorBase] Unexpected Status Code "
+            + "recieved from server.  Expected any value except '" + sCode
+            + "', received '" + resCode + "'");
+        return false;
+      }
+
+      TestUtil.logTrace("[WebValidatorBase] Status Code '" + sCode
+          + "' not found in response line!");
+    }
+
+    return true;
+  }
+
+  /**
+   * <code>checkSearchStrings</code> will scan the response for the configured
+   * strings that are to be expected in the response.
+   * <ul>
+   * <li>Check search strings</li>
+   * <ul>
+   * <li>
+   * <p>
+   * If list of Strings is null, return true.
+   * </p>
+   * </li>
+   * <li>
+   * <p>
+   * If list of Strings is not null, scan response body. If string is found,
+   * return true, otherwise display error and return false.
+   * </p>
+   * </li>
+   * </ul>
+   * </ul>
+   * <em>NOTE:</em> If there are multiple search strings, the search will be
+   * performed as such to preserve the order. For example, if the list of search
+   * strings contains two entities, the search for the second entity will be
+   * started after the index if the first match.
+   *
+   * @return boolen result of check
+   * @throws IOException
+   *           if an IO error occurs during validation
+   */
+  protected boolean checkSearchStrings() throws IOException {
+    List list = _case.getSearchStrings();
+    boolean found = true;
+    if (list != null && !list.isEmpty()) {
+      String responseBody = _res.getResponseBodyAsRawString();
+
+      String search = null;
+
+      for (int i = 0, n = list.size(), startIdx = 0, bodyLength = responseBody
+          .length(); i < n; i++) {
+
+        // set the startIdx to the same value as the body length
+        // and let the test fail (prevents index based runtime
+        // exceptions).
+        if (startIdx >= bodyLength) {
+          startIdx = bodyLength;
+        }
+
+        search = (String) list.get(i);
+        int searchIdx = responseBody.indexOf(search, startIdx);
+
+        TestUtil.logTrace(
+            "[WebValidatorBase] Scanning response for " + "search string: '"
+                + search + "' starting at index " + "location: " + startIdx);
+        if (searchIdx < 0) {
+          found = false;
+          StringBuffer sb = new StringBuffer(255);
+          sb.append("[WebValidatorBase] Unable to find the following ");
+          sb.append("search string in the server's ");
+          sb.append("response: '").append(search).append("' at index: ");
+          sb.append(startIdx);
+          sb.append("\n[WebValidatorBase] Server's response:\n");
+          sb.append("-------------------------------------------\n");
+          sb.append(responseBody);
+          sb.append("\n-------------------------------------------\n");
+          TestUtil.logErr(sb.toString());
+          break;
+        }
+
+        TestUtil.logTrace("[WebValidatorBase] Found search string: '" + search
+            + "' at index '" + searchIdx + "' in the server's " + "response");
+        // the new searchIdx is the old index plus the lenght of the
+        // search string.
+        startIdx = searchIdx + search.length();
+      }
+    }
+    return found;
+  }
+
+  /**
+   * <code>checkSearchStringsNoCase</code> will scan the response for the
+   * configured case insensitive strings that are to be expected in the
+   * response.
+   * <ul>
+   * <li>Check search strings</li>
+   * <ul>
+   * <li>
+   * <p>
+   * If list of Strings is null, return true.
+   * </p>
+   * </li>
+   * <li>
+   * <p>
+   * If list of Strings is not null, scan response body. If string is found,
+   * return true, otherwise display error and return false.
+   * </p>
+   * </li>
+   * </ul>
+   * </ul>
+   * <em>NOTE:</em> If there are multiple search strings, the search will be
+   * performed as such to preserve the order. For example, if the list of search
+   * strings contains two entities, the search for the second entity will be
+   * started after the index if the first match.
+   *
+   * @return boolen result of check
+   * @throws IOException
+   *           if an IO error occurs during validation
+   */
+  protected boolean checkSearchStringsNoCase() throws IOException {
+    List list = _case.getSearchStringsNoCase();
+    boolean found = true;
+    if (list != null && !list.isEmpty()) {
+      String responseBody = _res.getResponseBodyAsRawString();
+
+      String search = null;
+
+      for (int i = 0, n = list.size(), startIdx = 0, bodyLength = responseBody
+          .length(); i < n; i++) {
+
+        // set the startIdx to the same value as the body length
+        // and let the test fail (prevents index based runtime
+        // exceptions).
+        if (startIdx >= bodyLength) {
+          startIdx = bodyLength;
+        }
+
+        search = (String) list.get(i);
+        int searchIdx = responseBody.toLowerCase().indexOf(search.toLowerCase(),
+            startIdx);
+
+        TestUtil.logTrace(
+            "[WebValidatorBase] Scanning response for " + "search string: '"
+                + search + "' starting at index " + "location: " + startIdx);
+        if (searchIdx < 0) {
+          found = false;
+          StringBuffer sb = new StringBuffer(255);
+          sb.append("[WebValidatorBase] Unable to find the following ");
+          sb.append("search string in the server's ");
+          sb.append("response: '").append(search).append("' at index: ");
+          sb.append(startIdx);
+          sb.append("\n[WebValidatorBase] Server's response:\n");
+          sb.append("-------------------------------------------\n");
+          sb.append(responseBody);
+          sb.append("\n-------------------------------------------\n");
+          TestUtil.logErr(sb.toString());
+          break;
+        }
+
+        TestUtil.logTrace("[WebValidatorBase] Found search string: '" + search
+            + "' at index '" + searchIdx + "' in the server's " + "response");
+        // the new searchIdx is the old index plus the lenght of the
+        // search string.
+        startIdx = searchIdx + search.length();
+      }
+    }
+    return found;
+  }
+
+  /**
+   * <code>checkUnorderedSearchStrings</code> will scan the response for the
+   * configured strings that are to be expected in the response.
+   * <ul>
+   * <li>Check search strings</li>
+   * <ul>
+   * <li>
+   * <p>
+   * If list of Strings is null, return true.
+   * </p>
+   * </li>
+   * <li>
+   * <p>
+   * If list of Strings is not null, scan response body. If string is found,
+   * return true, otherwise display error and return false.
+   * </p>
+   * </li>
+   * </ul>
+   * </ul>
+   *
+   * @return boolen result of check
+   * @throws IOException
+   *           if an IO error occurs during validation
+   */
+  protected boolean checkUnorderedSearchStrings() throws IOException {
+    List list = _case.getUnorderedSearchStrings();
+    boolean found = true;
+    if (list != null && !list.isEmpty()) {
+      String responseBody = _res.getResponseBodyAsRawString();
+
+      String search = null;
+
+      for (int i = 0, n = list.size(); i < n; i++) {
+
+        search = (String) list.get(i);
+        int searchIdx = responseBody.indexOf(search);
+
+        TestUtil.logTrace("[WebValidatorBase] Scanning response for "
+            + "search string: '" + search + "'...");
+        if (searchIdx < 0) {
+          found = false;
+          StringBuffer sb = new StringBuffer(255);
+          sb.append("[WebValidatorBase] Unable to find the following ");
+          sb.append("search string in the server's ");
+          sb.append("response: '").append(search);
+          sb.append("\n[WebValidatorBase] Server's response:\n");
+          sb.append("-------------------------------------------\n");
+          sb.append(responseBody);
+          sb.append("\n-------------------------------------------\n");
+          TestUtil.logErr(sb.toString());
+          break;
+        }
+
+        TestUtil.logTrace("[WebValidatorBase] Found search string: '" + search
+            + "' at index '" + searchIdx + "' in the server's " + "response");
+      }
+    }
+    return found;
+  }
+
+  /**
+   * <code>checkUnexpectedSearchStrings</code> will scan the response for the
+   * configured strings that are not expected in the response.
+   * <ul>
+   * <li>Check unexpected search strings</li>
+   * <ul>
+   * <li>
+   * <p>
+   * If list of Strings is null, return true.
+   * </p>
+   * </li>
+   * <li>
+   * <p>
+   * If list of Strings is not null, scan response body. If string is not found,
+   * return true, otherwise display error and return false.
+   * <p>
+   * </li>
+   * </ul>
+   * </ul>
+   *
+   * @return boolen result of check
+   * @throws IOException
+   *           if an IO error occurs during validation
+   */
+  protected boolean checkUnexpectedSearchStrings() throws IOException {
+    List list = _case.getUnexpectedSearchStrings();
+    if (list != null && !list.isEmpty()) {
+      String responseBody = _res.getResponseBodyAsRawString();
+      Iterator iter = list.iterator();
+      while (iter.hasNext()) {
+        String search = (String) iter.next();
+        TestUtil.logTrace("[WebValidatorBase] Scanning response.  The following"
+            + " string should not be present in the response: '" + search
+            + "'");
+        if (responseBody.indexOf(search) > -1) {
+          StringBuffer sb = new StringBuffer(255);
+          sb.append("[WebValidatorBase] Found the following unexpected ");
+          sb.append("search string in the server's ");
+          sb.append("response: '").append(search).append("'");
+          sb.append("\n[WebValidatorBase] Server's response:\n");
+          sb.append("-------------------------------------------\n");
+          sb.append(responseBody);
+          sb.append("\n-------------------------------------------\n");
+          TestUtil.logErr(sb.toString());
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  /**
+   * <code>checkGoldenFile</code> compare the server's response with the
+   * configured goldenfile
+   * <ul>
+   * <li>Check the goldenfile</li>
+   * <ul>
+   * <li>
+   * <p>
+   * If goldenfile is null, return true.
+   * </p>
+   * </li>
+   * <li>
+   * <p>
+   * If goldenfile is not null, compare the goldenfile with the response. If
+   * equal, return true, otherwise display error and return false.
+   * <p>
+   * </li>
+   * </ul>
+   * </ul>
+   *
+   * @return boolen result of check
+   * @throws IOException
+   *           if an IO error occurs during validation
+   */
+  protected abstract boolean checkGoldenfile() throws IOException;
+
+  /**
+   * <code>checkReasonPhrase</code> will perform comparisons between the
+   * configued reason-phrase and that of the response.
+   * <ul>
+   * <li>Check reason-phrase</li>
+   * <ul>
+   * <li>
+   * <p>
+   * If configured reason-phrase is null, return true.
+   * </p>
+   * </li>
+   * <li>
+   * <p>
+   * If configured reason-phrase is not null, compare the reason-phrases with
+   * the response. If equal, return true, otherwise display error and return
+   * false.
+   * <p>
+   * </li>
+   * </ul>
+   * </ul>
+   *
+   * @return boolen result of check
+   */
+  protected boolean checkReasonPhrase() {
+    String sReason = _case.getReasonPhrase();
+    String resReason = _res.getReasonPhrase();
+
+    if (sReason == null) {
+      return true;
+    } else if (sReason.equalsIgnoreCase(resReason)) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * <code>checkExpectedHeaders</code> will check the response for the
+   * configured expected headers.
+   * <ul>
+   * <li>Check expected headers</li>
+   * <ul>
+   * <li>
+   * <p>
+   * If there are no expected headers, return true.
+   * </p>
+   * </li>
+   * <li>
+   * <p>
+   * If there are expected headers, scan the response for the expected headers.
+   * If all expected headers are found, return true, otherwise display an error
+   * and return false.
+   * <p>
+   * </li>
+   * </ul>
+   * </ul>
+   *
+   * @return boolen result of check
+   */
+  protected boolean checkExpectedHeaders() {
+    Header[] expected = _case.getExpectedHeaders();
+    if (isEmpty(expected)) {
+      return true;
+    } else {
+      boolean found = true;
+      Header currentHeader = null;
+      for (int i = 0; i < expected.length; i++) {
+        currentHeader = expected[i];
+        Header resHeader = _res.getResponseHeader(currentHeader.getName());
+        if (resHeader != null) {
+          Handler handler = HandlerFactory.getHandler(currentHeader.getName());
+          if (!handler.invoke(currentHeader, resHeader)) {
+            found = false;
+            break;
+          }
+        } else {
+          found = false;
+          break;
+        }
+      }
+      if (!found) {
+        StringBuffer sb = new StringBuffer(255);
+        sb.append("[WebValidatorBase] Unable to find the following header");
+        sb.append(" in the server's response: ");
+        sb.append(currentHeader.toExternalForm()).append("\n");
+        sb.append("[WebValidatorBase] Response headers recieved from");
+        sb.append(" server:");
+
+        Header[] resHeaders = _res.getResponseHeaders();
+        for (int i = 0; i < resHeaders.length; i++) {
+          sb.append("\n\tResponseHeader -> ");
+          sb.append(resHeaders[i].toExternalForm());
+        }
+        sb.append("\n");
+        TestUtil.logErr(sb.toString());
+
+        return false;
+      } else {
+        TestUtil.logTrace("[WebValidatorBase] Found expected header: "
+            + currentHeader.toExternalForm());
+        return true;
+      }
+    }
+  }
+
+  /**
+   * <code>checkUnexpectedHeaders</code> will check the response for the
+   * configured unexpected expected headers.
+   * <ul>
+   * <li>Check unexpected headers</li>
+   * <ul>
+   * <li>
+   * <p>
+   * If there are no configured unexpected headers, return true.
+   * </p>
+   * </li>
+   * <li>
+   * <p>
+   * If there are configured unexpected headers, scan the response for the
+   * unexpected headers. If the headers are not found, return true, otherwise
+   * display an error and return false.
+   * <p>
+   * </li>
+   * </ul>
+   * </ul>
+   *
+   * @return boolen result of check
+   */
+  protected boolean checkUnexpectedHeaders() {
+    Header[] unexpected = _case.getUnexpectedHeaders();
+    if (isEmpty(unexpected)) {
+      return true;
+    } else {
+      Header currentHeader = null;
+      for (int i = 0; i < unexpected.length; i++) {
+        currentHeader = unexpected[i];
+        String currName = currentHeader.getName();
+        String currValue = currentHeader.getValue();
+        Header resHeader = _res.getResponseHeader(currName);
+        if (resHeader != null) {
+          if (resHeader.getValue().equals(currValue)) {
+            StringBuffer sb = new StringBuffer(255);
+            sb.append("[WebValidatorBase] Unexpected header found in the ");
+            sb.append("server's response: ");
+            sb.append(currentHeader.toExternalForm()).append("\n");
+            sb.append("[WebValidatorBase] Response headers recieved from");
+            sb.append("server:");
+
+            Header[] resHeaders = _res.getResponseHeaders();
+            for (int j = 0; j < resHeaders.length; j++) {
+              sb.append("\n\tResponseHeader -> ");
+              sb.append(resHeaders[j].toExternalForm());
+            }
+            sb.append("\n");
+            TestUtil.logErr(sb.toString());
+
+            return false;
+          }
+        }
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Utility method to determine of the expected or unexpected headers are empty
+   * or not.
+   */
+  protected boolean isEmpty(Header[] headers) {
+    if (headers == null || headers.length == 0) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/client/asyncinvoker/JAXRSClientIT.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/client/asyncinvoker/JAXRSClientIT.java
new file mode 100644
index 0000000..bedbc29
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/client/asyncinvoker/JAXRSClientIT.java
@@ -0,0 +1,3258 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.ee.rs.client.asyncinvoker;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.io.InputStream;
+import java.io.IOException;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+import jakarta.ws.rs.tck.common.client.JaxrsCommonClient;
+import jakarta.ws.rs.tck.common.client.JdkLoggingFilter;
+
+import org.jboss.arquillian.junit5.ArquillianExtension;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.jboss.shrinkwrap.api.exporter.ZipExporter;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.AfterEach;
+
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.client.AsyncInvoker;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.client.InvocationCallback;
+import jakarta.ws.rs.client.WebTarget;
+import jakarta.ws.rs.core.GenericType;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.Response.Status;
+
+/*
+ * @class.setup_props: webServerHost;
+ *                     webServerPort;
+ */
+@ExtendWith(ArquillianExtension.class)
+public class JAXRSClientIT extends JaxrsCommonClient {
+
+  private static final long serialVersionUID = -696868584437674095L;
+
+  protected long millis;
+
+  protected int callbackResult = 0;
+
+  protected Throwable callbackException = null;
+
+  private final static String NONEXISTING_SITE = "somenonexisting.domain-site";
+
+  public JAXRSClientIT() {
+    setup();
+    setContextRoot("jaxrs_ee_rs_client_asyncinvoker_web/resource");
+  }
+
+  static final String[] METHODS = { "DELETE", "GET", "OPTIONS" };
+
+  static final String[] ENTITY_METHODS = { "PUT", "POST" };
+
+  @Deployment(testable = false)
+  public static WebArchive createDeployment() throws IOException{
+
+    InputStream inStream = JAXRSClientIT.class.getClassLoader().getResourceAsStream("jakarta/ws/rs/tck/ee/rs/client/asyncinvoker/web.xml.template");
+    // Replace the servlet_adaptor in web.xml.template with the System variable set as servlet adaptor
+    String webXml = editWebXmlString(inStream);
+
+    WebArchive archive = ShrinkWrap.create(WebArchive.class, "jaxrs_ee_rs_client_asyncinvoker_web.war");
+    archive.addClasses(TSAppConfig.class, Resource.class);
+    archive.setWebXML(new StringAsset(webXml));
+    return archive;
+
+  }
+
+  @BeforeEach
+  void logStartTest(TestInfo testInfo) {
+    TestUtil.logMsg("STARTING TEST : "+testInfo.getDisplayName());
+  }
+
+  @AfterEach
+  void logFinishTest(TestInfo testInfo) {
+    TestUtil.logMsg("FINISHED TEST : "+testInfo.getDisplayName());
+  }
+
+  /* Run test */
+  // --------------------------------------------------------------------
+  // ---------------------- DELETE --------------------------------------
+  // --------------------------------------------------------------------
+  /*
+   * @testName: deleteTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:375;
+   * 
+   * @test_Strategy: Invoke HTTP DELETE method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void deleteTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("delete");
+    Future<Response> future = async.delete();
+    checkFutureOkResponseNoTime(future);
+    //return future;
+  }
+
+  /*
+   * @testName: deleteWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:375;
+   * 
+   * @test_Strategy: Invoke HTTP DELETE method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void deleteWhileServerWaitTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("deleteandwait");
+    Future<Response> future = async.delete();
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: deleteThrowsExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:375;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void deleteThrowsExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("delete");
+    Future<Response> future = async.delete();
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: deleteWithStringClassWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:376;
+   * 
+   * @test_Strategy: Invoke HTTP DELETE method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void deleteWithStringClassWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("deleteandwait");
+    Future<String> future = async.delete(String.class);
+    checkFutureString(future, "delete");
+    //return future;
+  }
+
+  /*
+   * @testName: deleteWithResponseClassWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:376;
+   * 
+   * @test_Strategy: Invoke HTTP DELETE method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void deleteWithResponseClassWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("deleteandwait");
+    Future<Response> future = async.delete(Response.class);
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: deleteWithClassThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:376;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void deleteWithClassThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("delete");
+    Future<String> future = async.delete(String.class);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: deleteWithClassThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:376;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void deleteWithClassThrowsWebApplicationExceptionTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("deletenotok");
+    Future<String> future = async.delete(String.class);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: deleteWithClassThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:376;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void deleteWithClassThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("deletenotok");
+    Future<Response> future = async.delete(Response.class);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  /*
+   * @testName: deleteWithGenericTypeStringWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:377;
+   * 
+   * @test_Strategy: Invoke HTTP DELETE method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void deleteWithGenericTypeStringWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("deleteandwait");
+    GenericType<String> generic = createGeneric(String.class);
+    Future<String> future = async.delete(generic);
+    checkFutureString(future, "delete");
+    //return future;
+  }
+
+  /*
+   * @testName: deleteWithGenericTypeResponseWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:377;
+   * 
+   * @test_Strategy: Invoke HTTP DELETE method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void deleteWithGenericTypeResponseWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("deleteandwait");
+    GenericType<Response> generic = createGeneric(Response.class);
+    Future<Response> future = async.delete(generic);
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: deleteWithGenericTypeThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:377;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void deleteWithGenericTypeThrowsProcessingExceptionTest()
+      throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("delete");
+    GenericType<String> generic = createGeneric(String.class);
+    Future<String> future = async.delete(generic);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: deleteWithGenericTypeThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:377;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void deleteWithGenericTypeThrowsWebApplicationExceptionTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("deletenotok");
+    GenericType<String> generic = createGeneric(String.class);
+    Future<String> future = async.delete(generic);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName:
+   * deleteWithGenericTypeThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:377;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void deleteWithGenericTypeThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("deletenotok");
+    GenericType<Response> generic = createGeneric(Response.class);
+    Future<Response> future = async.delete(generic);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  /*
+   * @testName: deleteWithCallbackWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:378;
+   * 
+   * @test_Strategy: Invoke HTTP DELETE method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void deleteWithCallbackWhileServerWaitTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("deleteandwait");
+    InvocationCallback<Response> callback = createCallback(true);
+    Future<Response> future = async.delete(callback);
+    checkFutureOkResponse(future);
+    assertCallbackCall();
+    //return future;
+  }
+
+  /*
+   * @testName: deleteWithCallbackStringWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:378;
+   * 
+   * @test_Strategy: Invoke HTTP DELETE method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void deleteWithCallbackStringWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("deleteandwait");
+    InvocationCallback<String> callback = createStringCallback(true);
+    Future<String> future = async.delete(callback);
+    checkFutureString(future, "delete");
+    assertCallbackCall();
+    //return future;
+  }
+
+  /*
+   * @testName: deleteWithCallbackStringThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:378;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void deleteWithCallbackStringThrowsProcessingExceptionTest()
+      throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("deleteandwait");
+    InvocationCallback<String> callback = createStringCallback(false);
+    Future<String> future = async.delete(callback);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: deleteWithCallbackStringThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:378;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void deleteWithCallbackStringThrowsWebApplicationExceptionTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("deletenotok");
+    InvocationCallback<String> callback = createStringCallback(false);
+    Future<String> future = async.delete(callback);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: deleteWithCallbackThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:378;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void deleteWithCallbackThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("deletenotok");
+    InvocationCallback<Response> callback = createCallback(false);
+    Future<Response> future = async.delete(callback);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  // ------------------------------------------------------------------
+  // ---------------------------GET------------------------------------
+  // ------------------------------------------------------------------
+  /*
+   * @testName: getTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:379;
+   * 
+   * @test_Strategy: Invoke HTTP GET method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void getTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("get");
+    Future<Response> future = async.get();
+    checkFutureOkResponseNoTime(future);
+    //return future;
+  }
+
+  /*
+   * @testName: getWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:379;
+   * 
+   * @test_Strategy: Invoke HTTP GET method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void getWhileServerWaitTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("getandwait");
+    Future<Response> future = async.get();
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: getThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:379;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void getThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("get");
+    Future<Response> future = async.get();
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: getWithStringClassWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:380;
+   * 
+   * @test_Strategy: Invoke HTTP GET method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void getWithStringClassWhileServerWaitTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("getandwait");
+    Future<String> future = async.get(String.class);
+    checkFutureString(future, "get");
+    //return future;
+  }
+
+  /*
+   * @testName: getWithResponseClassWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:380;
+   * 
+   * @test_Strategy: Invoke HTTP GET method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void getWithResponseClassWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("getandwait");
+    Future<Response> future = async.get(Response.class);
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: getWithClassThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:380;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void getWithClassThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("get");
+    Future<String> future = async.get(String.class);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: getWithClassThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:380;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void getWithClassThrowsWebApplicationExceptionTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("getnotok");
+    Future<String> future = async.get(String.class);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: getWithClassThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:380;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void getWithClassThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("getnotok");
+    Future<Response> future = async.get(Response.class);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  /*
+   * @testName: getWithGenericTypeStringWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:381;
+   * 
+   * @test_Strategy: Invoke HTTP GET method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void getWithGenericTypeStringWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("getandwait");
+    GenericType<String> generic = createGeneric(String.class);
+    Future<String> future = async.get(generic);
+    checkFutureString(future, "get");
+    //return future;
+  }
+
+  /*
+   * @testName: getWithGenericTypeResponseWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:381;
+   * 
+   * @test_Strategy: Invoke HTTP GET method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void getWithGenericTypeResponseWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("getandwait");
+    GenericType<Response> generic = createGeneric(Response.class);
+    Future<Response> future = async.get(generic);
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: getWithGenericTypeThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:381;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void getWithGenericTypeThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("get");
+    GenericType<String> generic = createGeneric(String.class);
+    Future<String> future = async.get(generic);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: getWithGenericTypeThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:381;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void getWithGenericTypeThrowsWebApplicationExceptionTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("getnotok");
+    GenericType<String> generic = createGeneric(String.class);
+    Future<String> future = async.get(generic);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: getWithGenericTypeThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:381;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void getWithGenericTypeThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("getnotok");
+    GenericType<Response> generic = createGeneric(Response.class);
+    Future<Response> future = async.get(generic);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  /*
+   * @testName: getWithCallbackWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:382;
+   * 
+   * @test_Strategy: Invoke HTTP GET method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void getWithCallbackWhileServerWaitTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("getandwait");
+    InvocationCallback<Response> callback = createCallback(true);
+    Future<Response> future = async.get(callback);
+    checkFutureOkResponse(future);
+    assertCallbackCall();
+    //return future;
+  }
+
+  /*
+   * @testName: getWithCallbackStringWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:382;
+   * 
+   * @test_Strategy: Invoke HTTP GET method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void getWithCallbackStringWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("getandwait");
+    InvocationCallback<String> callback = createStringCallback(true);
+    Future<String> future = async.get(callback);
+    checkFutureString(future, "get");
+    assertCallbackCall();
+    //return future;
+  }
+
+  /*
+   * @testName: getWithCallbackStringThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:382;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void getWithCallbackStringThrowsProcessingExceptionTest()
+      throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("get");
+    InvocationCallback<String> callback = createStringCallback(false);
+    Future<String> future = async.get(callback);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: getWithCallbackStringThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:382;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void getWithCallbackStringThrowsWebApplicationExceptionTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("getnotok");
+    InvocationCallback<String> callback = createStringCallback(false);
+    Future<String> future = async.get(callback);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: getWithCallbackThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:382;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void getWithCallbackThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("getnotok");
+    InvocationCallback<Response> callback = createCallback(false);
+    Future<Response> future = async.get(callback);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  // ------------------------------------------------------------------
+  // ---------------------------HEAD-----------------------------------
+  // ------------------------------------------------------------------
+
+  /*
+   * @testName: headTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:383;
+   * 
+   * @test_Strategy: Invoke HTTP HEAD method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void headTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("head");
+    Future<Response> future = async.head();
+    checkFutureOkResponseNoTime(future);
+    //return future;
+  }
+
+  /*
+   * @testName: headWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:383;
+   * 
+   * @test_Strategy: Invoke HTTP HEAD method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void headWhileServerWaitTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("headandwait");
+    Future<Response> future = async.head();
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: headThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:383;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void headThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("head");
+    Future<Response> future = async.head();
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: headWithCallbackWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:384;
+   * 
+   * @test_Strategy: Invoke HTTP HEAD method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void headWithCallbackWhileServerWaitTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("headandwait");
+    InvocationCallback<Response> callback = createCallback(true);
+    Future<Response> future = async.head(callback);
+    checkFutureOkResponse(future);
+    assertCallbackCall();
+    //return future;
+  }
+
+  /*
+   * @testName: headWithCallbackStringThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:384;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void headWithCallbackStringThrowsProcessingExceptionTest()
+      throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("head");
+    InvocationCallback<Response> callback = createCallback(false);
+    Future<Response> future = async.head(callback);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  // ------------------------------------------------------------------
+  // ---------------------------METHOD-----------------------------------
+  // ------------------------------------------------------------------
+
+  /*
+   * @testName: methodTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:385;
+   * 
+   * @test_Strategy: Invoke an arbitrary method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void methodTest() throws Fault {
+    Future<Response> future = null;
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(method.toLowerCase());
+      future = async.method(method);
+      checkFutureOkResponseNoTime(future);
+    }
+    //return future;
+  }
+
+  /*
+   * @testName: methodWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:385;
+   * 
+   * @test_Strategy: Invoke an arbitrary method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void methodWhileServerWaitTest() throws Fault {
+    Future<Response> future = null;
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "andwait");
+      future = async.method(method);
+      checkFutureOkResponse(future);
+    }
+    //return future;
+  }
+
+  /*
+   * @testName: methodThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:385;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void methodThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    Future<Response> future = null;
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(method.toLowerCase());
+      future = async.method(method);
+      assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+    }
+  }
+
+  /*
+   * @testName: methodWithStringClassWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:386;
+   * 
+   * @test_Strategy: Invoke an arbitrary method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void methodWithStringClassWhileServerWaitTest()
+      throws Fault {
+    Future<String> future = null;
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "andwait");
+      future = async.method(method, String.class);
+      checkFutureString(future, method);
+    }
+    //return future;
+  }
+
+  /*
+   * @testName: methodWithResponseClassWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:386;
+   * 
+   * @test_Strategy: Invoke an arbitrary method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void methodWithResponseClassWhileServerWaitTest()
+      throws Fault {
+    Future<Response> future = null;
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "andwait");
+      future = async.method(method, Response.class);
+      checkFutureOkResponse(future);
+    }
+    //return future;
+  }
+
+  /*
+   * @testName: methodWithClassThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:386;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void methodWithClassThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    Future<String> future = null;
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(method.toLowerCase());
+      future = async.method(method, String.class);
+      assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+    }
+  }
+
+  /*
+   * @testName: methodWithClassThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:386;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void methodWithClassThrowsWebApplicationExceptionTest() throws Fault {
+    Future<String> future = null;
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "notok");
+      future = async.method(method, String.class);
+      assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+    }
+  }
+
+  /*
+   * @testName: methodWithClassThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:386;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void methodWithClassThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    Future<Response> future = null;
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "notok");
+      future = async.method(method, Response.class);
+      checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+    }
+  }
+
+  /*
+   * @testName: methodWithGenericTypeStringWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:387;
+   * 
+   * @test_Strategy: Invoke an arbitrary method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void methodWithGenericTypeStringWhileServerWaitTest()
+      throws Fault {
+    GenericType<String> generic = createGeneric(String.class);
+    Future<String> future = null;
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "andwait");
+      future = async.method(method, generic);
+      checkFutureString(future, method);
+    }
+    //return future;
+  }
+
+  /*
+   * @testName: methodWithGenericTypeResponseWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:387;
+   * 
+   * @test_Strategy: Invoke an arbitrary method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void methodWithGenericTypeResponseWhileServerWaitTest()
+      throws Fault {
+    GenericType<Response> generic = createGeneric(Response.class);
+    Future<Response> future = null;
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "andwait");
+      future = async.method(method, generic);
+      checkFutureOkResponse(future);
+    }
+    //return future;
+  }
+
+  /*
+   * @testName: methodWithGenericTypeThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:387;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void methodWithGenericTypeThrowsProcessingExceptionTest()
+      throws Fault {
+    _hostname = NONEXISTING_SITE;
+    Future<Response> future = null;
+    GenericType<Response> generic = createGeneric(Response.class);
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(method.toLowerCase());
+      future = async.method(method, generic);
+      assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+    }
+  }
+
+  /*
+   * @testName: methodWithGenericTypeThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:387;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void methodWithGenericTypeThrowsWebApplicationExceptionTest()
+      throws Fault {
+    Future<String> future = null;
+    GenericType<String> generic = createGeneric(String.class);
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "notok");
+      future = async.method(method, generic);
+      assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+    }
+  }
+
+  /*
+   * @testName:
+   * methodWithGenericTypeThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:387;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void methodWithGenericTypeThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    Future<Response> future = null;
+    GenericType<Response> generic = createGeneric(Response.class);
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "notok");
+      future = async.method(method, generic);
+      checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+    }
+  }
+
+  /*
+   * @testName: methodWithCallbackWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:388;
+   * 
+   * @test_Strategy: Invoke an arbitrary method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void methodWithCallbackWhileServerWaitTest() throws Fault {
+    InvocationCallback<Response> callback = createCallback(true);
+    Future<Response> future = null;
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "andwait");
+      future = async.method(method, callback);
+      checkFutureOkResponse(future);
+      assertCallbackCall();
+    }
+    //return future;
+  }
+
+  /*
+   * @testName: methodWithCallbackStringWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:388;
+   * 
+   * @test_Strategy: Invoke an arbitrary method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void methodWithCallbackStringWhileServerWaitTest()
+      throws Fault {
+    InvocationCallback<String> callback = createStringCallback(true);
+    Future<String> future = null;
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "andwait");
+      future = async.method(method, callback);
+      checkFutureString(future, method);
+      assertCallbackCall();
+    }
+    //return future;
+  }
+
+  /*
+   * @testName: methodWithCallbackThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:388;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void methodWithCallbackThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    Future<String> future = null;
+    InvocationCallback<String> callback = createStringCallback(false);
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(method.toLowerCase());
+      future = async.method(method, callback);
+      assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+    }
+  }
+
+  /*
+   * @testName: methodWithCallbackThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:388;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void methodWithCallbackThrowsWebApplicationExceptionTest()
+      throws Fault {
+    Future<String> future = null;
+    InvocationCallback<String> callback = createStringCallback(false);
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "notok");
+      future = async.method(method, callback);
+      assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+    }
+  }
+
+  /*
+   * @testName: methodWithCallbackThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:388;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void methodWithCallbackThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    Future<Response> future = null;
+    InvocationCallback<Response> callback = createCallback(false);
+    for (String method : METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "notok");
+      future = async.method(method, callback);
+      checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+    }
+  }
+
+  /*
+   * @testName: methodWithEntityWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:389;
+   * 
+   * @test_Strategy: Invoke an arbitrary method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void methodWithEntityWhileServerWaitTest() throws Fault {
+    Future<Response> future = null;
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "andwait");
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity);
+      checkFutureOkResponse(future);
+    }
+    //return future;
+  }
+
+  /*
+   * @testName: methodWithEntityThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:389;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void methodWithEntityThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    Future<Response> future = null;
+    for (String method : ENTITY_METHODS) {
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      AsyncInvoker async = startAsyncInvokerForMethod(method.toLowerCase());
+      future = async.method(method, entity);
+      assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+    }
+  }
+
+  /*
+   * @testName: methodWithStringClassWithEntityWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:390;
+   * 
+   * @test_Strategy: Invoke an arbitrary method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void methodWithStringClassWithEntityWhileServerWaitTest()
+      throws Fault {
+    Future<String> future = null;
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "andwait");
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity, String.class);
+      checkFutureString(future, method);
+    }
+    //return future;
+  }
+
+  /*
+   * @testName: methodWithResponseClassWithEntityWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:390;
+   * 
+   * @test_Strategy: Invoke an arbitrary method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void methodWithResponseClassWithEntityWhileServerWaitTest()
+      throws Fault {
+    Future<Response> future = null;
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "andwait");
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity, Response.class);
+      checkFutureOkResponse(future);
+    }
+    //return future;
+  }
+
+  /*
+   * @testName: methodWithClassWithEntityThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:390;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void methodWithClassWithEntityThrowsProcessingExceptionTest()
+      throws Fault {
+    _hostname = NONEXISTING_SITE;
+    Future<String> future = null;
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(method.toLowerCase());
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity, String.class);
+      assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+    }
+  }
+
+  /*
+   * @testName: methodWithClassWithEntityThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:390;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void methodWithClassWithEntityThrowsWebApplicationExceptionTest()
+      throws Fault {
+    Future<String> future = null;
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "notok");
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity, String.class);
+      assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+    }
+  }
+
+  /*
+   * @testName:
+   * methodWithClassWithEntityThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:390;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void methodWithClassWithEntityThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    Future<Response> future = null;
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "notok");
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity, Response.class);
+      checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+    }
+  }
+
+  /*
+   * @testName: methodWithGenericTypeStringWithEntityWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:391;
+   * 
+   * @test_Strategy: Invoke an arbitrary method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void methodWithGenericTypeStringWithEntityWhileServerWaitTest()
+      throws Fault {
+    Future<String> future = null;
+    GenericType<String> generic = createGeneric(String.class);
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "andwait");
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity, generic);
+      checkFutureString(future, method);
+    }
+    //return future;
+  }
+
+  /*
+   * @testName: methodWithGenericTypeResponseWithEntityWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:391;
+   * 
+   * @test_Strategy: Invoke an arbitrary method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void methodWithGenericTypeResponseWithEntityWhileServerWaitTest()
+      throws Fault {
+    Future<Response> future = null;
+    GenericType<Response> generic = createGeneric(Response.class);
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "andwait");
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity, generic);
+      checkFutureOkResponse(future);
+    }
+    //return future;
+  }
+
+  /*
+   * @testName: methodWithGenericTypeWithEntityThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:391;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void methodWithGenericTypeWithEntityThrowsProcessingExceptionTest()
+      throws Fault {
+    _hostname = NONEXISTING_SITE;
+    GenericType<String> generic = createGeneric(String.class);
+    Future<String> future = null;
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(method.toLowerCase());
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity, generic);
+      assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+    }
+  }
+
+  /*
+   * @testName: methodWithGenericTypeWithEntityThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:391;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void methodWithGenericTypeWithEntityThrowsWebApplicationExceptionTest()
+      throws Fault {
+    Future<String> future = null;
+    GenericType<String> generic = createGeneric(String.class);
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "notok");
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity, generic);
+      assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+    }
+  }
+
+  /*
+   * @testName:
+   * methodWithGenericTypeWithEntityThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:391;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void methodWithGenericTypeWithEntityThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    Future<Response> future = null;
+    GenericType<Response> generic = createGeneric(Response.class);
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "notok");
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity, generic);
+      checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+    }
+  }
+
+  /*
+   * @testName: methodWithCallbackWithEntityWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:392;
+   * 
+   * @test_Strategy: Invoke an arbitrary method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void methodWithCallbackWithEntityWhileServerWaitTest()
+      throws Fault {
+    Future<Response> future = null;
+    InvocationCallback<Response> callback = createCallback(true);
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "andwait");
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity, callback);
+      checkFutureOkResponse(future);
+      assertCallbackCall();
+    }
+    //return future;
+  }
+
+  /*
+   * @testName: methodWithCallbackStringWithEntityWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:392;
+   * 
+   * @test_Strategy: Invoke an arbitrary method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void methodWithCallbackStringWithEntityWhileServerWaitTest()
+      throws Fault {
+    Future<String> future = null;
+    InvocationCallback<String> callback = createStringCallback(true);
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "andwait");
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity, callback);
+      checkFutureString(future, method);
+      assertCallbackCall();
+    }
+    //return future;
+  }
+
+  /*
+   * @testName: methodWithCallbackWithEntityThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:392;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void methodWithCallbackWithEntityThrowsProcessingExceptionTest()
+      throws Fault {
+    _hostname = NONEXISTING_SITE;
+    InvocationCallback<String> callback = createStringCallback(false);
+    Future<String> future = null;
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(method.toLowerCase());
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity, callback);
+      assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+    }
+  }
+
+  /*
+   * @testName: methodWithCallbackWithEntityThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:392;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void methodWithCallbackWithEntityThrowsWebApplicationExceptionTest()
+      throws Fault {
+    Future<String> future = null;
+    InvocationCallback<String> callback = createStringCallback(false);
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "notok");
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity, callback);
+      assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+    }
+  }
+
+  /*
+   * @testName:
+   * methodWithCallbackWithEntityThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:392;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void methodWithCallbackWithEntityThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    Future<Response> future = null;
+    InvocationCallback<Response> callback = createCallback(false);
+    for (String method : ENTITY_METHODS) {
+      AsyncInvoker async = startAsyncInvokerForMethod(
+          method.toLowerCase() + "notok");
+      Entity<String> entity = Entity.entity(method, MediaType.WILDCARD_TYPE);
+      future = async.method(method, entity, callback);
+      checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+    }
+  }
+
+  // ------------------------------------------------------------------
+  // ---------------------------OPTIONS--------------------------------
+  // ------------------------------------------------------------------
+
+  /*
+   * @testName: optionsTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:393;
+   * 
+   * @test_Strategy: Invoke HTTP options method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void optionsTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("options");
+    Future<Response> future = async.options();
+    checkFutureOkResponseNoTime(future);
+    //return future;
+  }
+
+  /*
+   * @testName: optionsWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:393;
+   * 
+   * @test_Strategy: Invoke HTTP options method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void optionsWhileServerWaitTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("optionsandwait");
+    Future<Response> future = async.options();
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: optionsThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:393;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void optionsThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("options");
+    Future<Response> future = async.options();
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: optionsWithStringClassWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:394;
+   * 
+   * @test_Strategy: Invoke HTTP options method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void optionsWithStringClassWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("optionsandwait");
+    Future<String> future = async.options(String.class);
+    checkFutureString(future, "options");
+    //return future;
+  }
+
+  /*
+   * @testName: optionsWithResponseClassWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:394;
+   * 
+   * @test_Strategy: Invoke HTTP options method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void optionsWithResponseClassWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("optionsandwait");
+    Future<Response> future = async.options(Response.class);
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: optionsWithClassThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:394;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void optionsWithClassThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("options");
+    Future<String> future = async.options(String.class);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: optionsWithClassThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:394;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void optionsWithClassThrowsWebApplicationExceptionTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("optionsnotok");
+    Future<String> future = async.options(String.class);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: optionsWithClassThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:394;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void optionsWithClassThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("optionsnotok");
+    Future<Response> future = async.options(Response.class);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  /*
+   * @testName: optionsWithGenericTypeStringWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:395;
+   * 
+   * @test_Strategy: Invoke HTTP options method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void optionsWithGenericTypeStringWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("optionsandwait");
+    GenericType<String> generic = createGeneric(String.class);
+    Future<String> future = async.options(generic);
+    checkFutureString(future, "options");
+    //return future;
+  }
+
+  /*
+   * @testName: optionsWithGenericTypeResponseWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:395;
+   * 
+   * @test_Strategy: Invoke HTTP options method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void optionsWithGenericTypeResponseWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("optionsandwait");
+    GenericType<Response> generic = createGeneric(Response.class);
+    Future<Response> future = async.options(generic);
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: optionsWithGenericTypeThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:395;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void optionsWithGenericTypeThrowsProcessingExceptionTest()
+      throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("options");
+    GenericType<String> generic = createGeneric(String.class);
+    Future<String> future = async.options(generic);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: optionsWithGenericTypeThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:395;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void optionsWithGenericTypeThrowsWebApplicationExceptionTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("optionsnotok");
+    GenericType<String> generic = createGeneric(String.class);
+    Future<String> future = async.options(generic);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName:
+   * optionsWithGenericTypeThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:395;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void optionsWithGenericTypeThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("optionsnotok");
+    GenericType<Response> generic = createGeneric(Response.class);
+    Future<Response> future = async.options(generic);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  /*
+   * @testName: optionsWithCallbackWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:396;
+   * 
+   * @test_Strategy: Invoke HTTP options method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void optionsWithCallbackWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("optionsandwait");
+    InvocationCallback<Response> callback = createCallback(true);
+    Future<Response> future = async.options(callback);
+    checkFutureOkResponse(future);
+    assertCallbackCall();
+    //return future;
+  }
+
+  /*
+   * @testName: optionsWithStringCallbackWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:396;
+   * 
+   * @test_Strategy: Invoke HTTP options method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void optionsWithStringCallbackWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("optionsandwait");
+    InvocationCallback<String> callback = createStringCallback(true);
+    Future<String> future = async.options(callback);
+    checkFutureString(future, "options");
+    assertCallbackCall();
+    //return future;
+  }
+
+  /*
+   * @testName: optionsWithCallbackThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:396;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void optionsWithCallbackThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("options");
+    InvocationCallback<String> callback = createStringCallback(false);
+    Future<String> future = async.options(callback);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: optionsWithCallbackThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:396;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void optionsWithCallbackThrowsWebApplicationExceptionTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("optionsnotok");
+    InvocationCallback<String> callback = createStringCallback(false);
+    Future<String> future = async.options(callback);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName:
+   * optionsWithCallbackThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:396;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void optionsWithCallbackThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("optionsnotok");
+    InvocationCallback<Response> callback = createCallback(false);
+    Future<Response> future = async.options(callback);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  // ------------------------------------------------------------------
+  // ---------------------------POST-----------------------------------
+  // ------------------------------------------------------------------
+
+  /*
+   * @testName: postTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:397;
+   * 
+   * @test_Strategy: Invoke HTTP post method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void postTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("post");
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    Future<Response> future = async.post(entity);
+    checkFutureOkResponseNoTime(future);
+    //return future;
+  }
+
+  /*
+   * @testName: postWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:397;
+   * 
+   * @test_Strategy: Invoke HTTP post method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void postWhileServerWaitTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("postandwait");
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    Future<Response> future = async.post(entity);
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: postThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:397;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void postThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("post");
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    Future<Response> future = async.post(entity);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: postWithStringClassWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:398;
+   * 
+   * @test_Strategy: Invoke HTTP post method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void postWithStringClassWhileServerWaitTest() throws Fault {
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("postandwait");
+    Future<String> future = async.post(entity, String.class);
+    checkFutureString(future, "post");
+    //return future;
+  }
+
+  /*
+   * @testName: postWithResponseClassWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:398;
+   * 
+   * @test_Strategy: Invoke HTTP post method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void postWithResponseClassWhileServerWaitTest()
+      throws Fault {
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("postandwait");
+    Future<Response> future = async.post(entity, Response.class);
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: postWithClassThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:398;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void postWithClassThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("post");
+    Future<String> future = async.post(entity, String.class);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: postWithClassThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:398;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void postWithClassThrowsWebApplicationExceptionTest() throws Fault {
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("postnotok");
+    Future<String> future = async.post(entity, String.class);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: postWithClassThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:398;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void postWithClassThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("postnotok");
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    Future<Response> future = async.post(entity, Response.class);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  /*
+   * @testName: postWithGenericTypeStringWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:399;
+   * 
+   * @test_Strategy: Invoke HTTP post method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void postWithGenericTypeStringWhileServerWaitTest()
+      throws Fault {
+    GenericType<String> generic = createGeneric(String.class);
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("postandwait");
+    Future<String> future = async.post(entity, generic);
+    checkFutureString(future, "post");
+    //return future;
+  }
+
+  /*
+   * @testName: postWithGenericTypeResponseWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:399;
+   * 
+   * @test_Strategy: Invoke HTTP post method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void postWithGenericTypeResponseWhileServerWaitTest()
+      throws Fault {
+    GenericType<Response> generic = createGeneric(Response.class);
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("postandwait");
+    Future<Response> future = async.post(entity, generic);
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: postWithGenericTypeThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:399;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void postWithGenericTypeThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    GenericType<String> generic = createGeneric(String.class);
+    AsyncInvoker async = startAsyncInvokerForMethod("post");
+    Future<String> future = async.post(entity, generic);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: postWithGenericTypeThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:399;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void postWithGenericTypeThrowsWebApplicationExceptionTest()
+      throws Fault {
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    GenericType<String> generic = createGeneric(String.class);
+    AsyncInvoker async = startAsyncInvokerForMethod("postnotok");
+    Future<String> future = async.post(entity, generic);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName:
+   * postWithGenericTypeThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:399;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void postWithGenericTypeThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("postnotok");
+    GenericType<Response> generic = createGeneric(Response.class);
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    Future<Response> future = async.post(entity, generic);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  /*
+   * @testName: postWithCallbackWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:400;
+   * 
+   * @test_Strategy: Invoke HTTP post method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void postWithCallbackWhileServerWaitTest() throws Fault {
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    InvocationCallback<Response> callback = createCallback(true);
+    AsyncInvoker async = startAsyncInvokerForMethod("postandwait");
+    Future<Response> future = async.post(entity, callback);
+    checkFutureOkResponse(future);
+    assertCallbackCall();
+    //return future;
+  }
+
+  /*
+   * @testName: postWithCallbackThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:400;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void postWithCallbackThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    InvocationCallback<String> callback = createStringCallback(false);
+    AsyncInvoker async = startAsyncInvokerForMethod("post");
+    Future<String> future = async.post(entity, callback);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: postWithCallbackThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:400;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void postWithCallbackThrowsWebApplicationExceptionTest() throws Fault {
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    InvocationCallback<String> callback = createStringCallback(false);
+    AsyncInvoker async = startAsyncInvokerForMethod("postnotok");
+    Future<String> future = async.post(entity, callback);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: postWithCallbackThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:400;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void postWithCallbackThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("postnotok");
+    InvocationCallback<Response> callback = createCallback(false);
+    Entity<String> entity = Entity.entity("post", MediaType.WILDCARD_TYPE);
+    Future<Response> future = async.post(entity, callback);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  // ------------------------------------------------------------------
+  // ---------------------------PUT -----------------------------------
+  // ------------------------------------------------------------------
+
+  /*
+   * @testName: putTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:401;
+   * 
+   * @test_Strategy: Invoke HTTP PUT method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void putTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("put");
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    Future<Response> future = async.put(entity);
+    checkFutureOkResponseNoTime(future);
+    //return future;
+  }
+
+  /*
+   * @testName: putWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:401;
+   * 
+   * @test_Strategy: Invoke HTTP PUT method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void putWhileServerWaitTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("putandwait");
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    Future<Response> future = async.put(entity);
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: putThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:401;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void putThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("put");
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    Future<Response> future = async.put(entity);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: putWithStringClassWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:402;
+   * 
+   * @test_Strategy: Invoke HTTP put method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void putWithStringClassWhileServerWaitTest() throws Fault {
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("putandwait");
+    Future<String> future = async.put(entity, String.class);
+    checkFutureString(future, "put");
+    //return future;
+  }
+
+  /*
+   * @testName: putWithResponseClassWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:402;
+   * 
+   * @test_Strategy: Invoke HTTP put method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void putWithResponseClassWhileServerWaitTest()
+      throws Fault {
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("putandwait");
+    Future<Response> future = async.put(entity, Response.class);
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: putWithClassThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:402;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void putWithClassThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("put");
+    Future<String> future = async.put(entity, String.class);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: putWithClassThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:402;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void putWithClassThrowsWebApplicationExceptionTest() throws Fault {
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("putnotok");
+    Future<String> future = async.put(entity, String.class);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: putWithClassThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:402;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void putWithClassThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("putnotok");
+    Future<Response> future = async.put(entity, Response.class);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  /*
+   * @testName: putWithGenericTypeStringWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:403;
+   * 
+   * @test_Strategy: Invoke HTTP put method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void putWithGenericTypeStringWhileServerWaitTest()
+      throws Fault {
+    GenericType<String> generic = createGeneric(String.class);
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("putandwait");
+    Future<String> future = async.put(entity, generic);
+    checkFutureString(future, "put");
+    //return future;
+  }
+
+  /*
+   * @testName: putWithGenericTypeResponseWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:403;
+   * 
+   * @test_Strategy: Invoke HTTP put method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void putWithGenericTypeResponseWhileServerWaitTest()
+      throws Fault {
+    GenericType<Response> generic = createGeneric(Response.class);
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("putandwait");
+    Future<Response> future = async.put(entity, generic);
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: putWithGenericTypeThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:403;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void putWithGenericTypeThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    GenericType<String> generic = createGeneric(String.class);
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("put");
+    Future<String> future = async.put(entity, generic);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: putWithGenericTypeThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:403;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void putWithGenericTypeThrowsWebApplicationExceptionTest()
+      throws Fault {
+    GenericType<String> generic = createGeneric(String.class);
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("putnotok");
+    Future<String> future = async.put(entity, generic);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: putWithGenericTypeThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:403;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void putWithGenericTypeThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("putnotok");
+    GenericType<Response> generic = createGeneric(Response.class);
+    Future<Response> future = async.put(entity, generic);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  /*
+   * @testName: putWithCallbackWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:404;
+   * 
+   * @test_Strategy: Invoke HTTP put method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void putWithCallbackWhileServerWaitTest() throws Fault {
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    InvocationCallback<Response> callback = createCallback(true);
+    AsyncInvoker async = startAsyncInvokerForMethod("putandwait");
+    Future<Response> future = async.put(entity, callback);
+    checkFutureOkResponse(future);
+    assertCallbackCall();
+    //return future;
+  }
+
+  /*
+   * @testName: putWithStringCallbackWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:404;
+   * 
+   * @test_Strategy: Invoke HTTP put method for the current request
+   * asynchronously.
+   */
+  @Test
+  public void putWithStringCallbackWhileServerWaitTest()
+      throws Fault {
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    InvocationCallback<String> callback = createStringCallback(true);
+    AsyncInvoker async = startAsyncInvokerForMethod("putandwait");
+    Future<String> future = async.put(entity, callback);
+    checkFutureString(future, "put");
+    assertCallbackCall();
+    //return future;
+  }
+
+  /*
+   * @testName: putWithCallbackThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:404;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void putWithCallbackThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    InvocationCallback<String> callback = createStringCallback(false);
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("put");
+    Future<String> future = async.put(entity, callback);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: putWithCallbackThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:404;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void putWithCallbackThrowsWebApplicationExceptionTest() throws Fault {
+    InvocationCallback<String> callback = createStringCallback(false);
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("putnotok");
+    Future<String> future = async.put(entity, callback);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: putWithCallbackThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:404;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void putWithCallbackThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    Entity<String> entity = Entity.entity("put", MediaType.WILDCARD_TYPE);
+    AsyncInvoker async = startAsyncInvokerForMethod("putnotok");
+    InvocationCallback<Response> callback = createCallback(false);
+    Future<Response> future = async.put(entity, callback);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  // ------------------------------------------------------------------
+  // ---------------------------TRACE -----------------------------------
+  // ------------------------------------------------------------------
+
+  /*
+   * @testName: traceTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:405;
+   * 
+   * @test_Strategy: Invoke HTTP trace method for the current request
+   * asynchronously.
+   */
+  //@Test
+  public void traceTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("trace");
+    Future<Response> future = async.trace();
+    checkFutureOkResponseNoTime(future);
+    //return future;
+  }
+
+  /*
+   * @testName: traceWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:405;
+   * 
+   * @test_Strategy: Invoke HTTP trace method for the current request
+   * asynchronously.
+   */
+  //@Test
+  public void traceWhileServerWaitTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("traceandwait");
+    Future<Response> future = async.trace();
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: traceThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:405;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void traceThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("trace");
+    Future<Response> future = async.trace();
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: traceWithStringClassWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:406;
+   * 
+   * @test_Strategy: Invoke HTTP trace method for the current request
+   * asynchronously.
+   */
+  //@Test
+  public void traceWithStringClassWhileServerWaitTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("traceandwait");
+    Future<String> future = async.trace(String.class);
+    checkFutureString(future, "trace");
+    //return future;
+  }
+
+  /*
+   * @testName: traceWithResponseClassWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:406;
+   * 
+   * @test_Strategy: Invoke HTTP trace method for the current request
+   * asynchronously.
+   */
+  //@Test
+  public void traceWithResponseClassWhileServerWaitTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("traceandwait");
+    Future<Response> future = async.trace(Response.class);
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: traceWithClassThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:406;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void traceWithClassThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    AsyncInvoker async = startAsyncInvokerForMethod("trace");
+    Future<String> future = async.trace(String.class);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: traceWithClassThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:406;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void traceWithClassThrowsWebApplicationExceptionTest() throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("tracenotok");
+    Future<String> future = async.trace(String.class);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: traceWithClassThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:406;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  //@Test
+  public void traceWithClassThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("tracenotok");
+    Future<Response> future = async.trace(Response.class);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  /*
+   * @testName: traceWithGenericTypeStringWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:407;
+   * 
+   * @test_Strategy: Invoke HTTP trace method for the current request
+   * asynchronously.
+   */
+  //@Test
+  public void traceWithGenericTypeStringWhileServerWaitTest()
+      throws Fault {
+    GenericType<String> generic = createGeneric(String.class);
+    AsyncInvoker async = startAsyncInvokerForMethod("traceandwait");
+    Future<String> future = async.trace(generic);
+    checkFutureString(future, "trace");
+    //return future;
+  }
+
+  /*
+   * @testName: traceWithGenericTypeResponseWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:407;
+   * 
+   * @test_Strategy: Invoke HTTP trace method for the current request
+   * asynchronously.
+   */
+  //@Test
+  public void traceWithGenericTypeResponseWhileServerWaitTest()
+      throws Fault {
+    GenericType<Response> generic = createGeneric(Response.class);
+    AsyncInvoker async = startAsyncInvokerForMethod("traceandwait");
+    Future<Response> future = async.trace(generic);
+    checkFutureOkResponse(future);
+    //return future;
+  }
+
+  /*
+   * @testName: traceWithGenericTypeThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:407;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void traceWithGenericTypeThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    GenericType<String> generic = createGeneric(String.class);
+    AsyncInvoker async = startAsyncInvokerForMethod("trace");
+    Future<String> future = async.trace(generic);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: traceWithGenericTypeThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:407;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void traceWithGenericTypeThrowsWebApplicationExceptionTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("tracenotok");
+    GenericType<String> generic = createGeneric(String.class);
+    Future<String> future = async.trace(generic);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName:
+   * traceWithGenericTypeThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:407;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  //@Test
+  public void traceWithGenericTypeThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("tracenotok");
+    GenericType<Response> generic = createGeneric(Response.class);
+    Future<Response> future = async.trace(generic);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  /*
+   * @testName: traceWithCallbackWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:408;
+   * 
+   * @test_Strategy: Invoke HTTP trace method for the current request
+   * asynchronously.
+   */
+  //@Test
+  public void traceWithCallbackWhileServerWaitTest() throws Fault {
+    InvocationCallback<Response> callback = createCallback(true);
+    AsyncInvoker async = startAsyncInvokerForMethod("traceandwait");
+    Future<Response> future = async.trace(callback);
+    checkFutureOkResponse(future);
+    assertCallbackCall();
+    //return future;
+  }
+
+  /*
+   * @testName: traceWithStringCallbackWhileServerWaitTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:408;
+   * 
+   * @test_Strategy: Invoke HTTP trace method for the current request
+   * asynchronously.
+   */
+  //@Test
+  public void traceWithStringCallbackWhileServerWaitTest()
+      throws Fault {
+    InvocationCallback<String> callback = createStringCallback(true);
+    AsyncInvoker async = startAsyncInvokerForMethod("traceandwait");
+    Future<String> future = async.trace(callback);
+    checkFutureString(future, "trace");
+    assertCallbackCall();
+    //return future;
+  }
+
+  /*
+   * @testName: traceWithCallbackThrowsProcessingExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:408;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps an
+   * jakarta.ws.rs.ProcessingException thrown in case of an invocation processing
+   * failure.
+   */
+  @Test
+  public void traceWithCallbackThrowsProcessingExceptionTest() throws Fault {
+    _hostname = NONEXISTING_SITE;
+    InvocationCallback<String> callback = createStringCallback(false);
+    AsyncInvoker async = startAsyncInvokerForMethod("trace");
+    Future<String> future = async.trace(callback);
+    assertExceptionWithProcessingExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: traceWithCallbackThrowsWebApplicationExceptionTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:408;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  @Test
+  public void traceWithCallbackThrowsWebApplicationExceptionTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("tracenotok");
+    InvocationCallback<String> callback = createStringCallback(false);
+    Future<String> future = async.trace(callback);
+    assertExceptionWithWebApplicationExceptionIsThrownAndLog(future);
+  }
+
+  /*
+   * @testName: traceWithCallbackThrowsNoWebApplicationExceptionForResponseTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:408;
+   * 
+   * @test_Strategy: Note that calling the Future.get() method on the returned
+   * Future instance may throw an ExecutionException that wraps a
+   * WebApplicationException or one of its subclasses thrown in case the
+   * received response status code is not successful and the specified response
+   * type is not Response.
+   */
+  //@Test
+  public void traceWithCallbackThrowsNoWebApplicationExceptionForResponseTest()
+      throws Fault {
+    AsyncInvoker async = startAsyncInvokerForMethod("tracenotok");
+    InvocationCallback<Response> callback = createCallback(false);
+    Future<Response> future = async.trace(callback);
+    checkFutureStatusResponseNoTime(future, Status.NOT_ACCEPTABLE);
+  }
+
+  // ///////////////////////////////////////////////////////////////////////
+  // utility methods
+
+  protected String getUrl(String method) {
+    StringBuilder url = new StringBuilder();
+    url.append("http://").append(_hostname).append(":").append(_port);
+    url.append("/").append(getContextRoot()).append("/").append(method);
+    return url.toString();
+  }
+
+  /**
+   * Create AsyncInvoker for given resource method and start time
+   */
+  protected AsyncInvoker startAsyncInvokerForMethod(String methodName) {
+    Client client = ClientBuilder.newClient();
+    client.register(new JdkLoggingFilter(false));
+    WebTarget target = client.target(getUrl(methodName));
+    AsyncInvoker async = target.request().async();
+    setStartTime();
+    return async;
+  }
+
+  protected void assertOkAndLog(Response response, Status status) throws Fault {
+    assertTrue(response.getStatus() == status.getStatusCode(),
+        "Returned unexpected status" +response.getStatus());
+    String msg = new StringBuilder().append("Returned status ")
+        .append(status.getStatusCode()).append(" (").append(status.name())
+        .append(")").toString();
+    TestUtil.logMsg(msg);
+  }
+
+  protected void checkFutureOkResponseNoTime(Future<Response> future)
+      throws Fault {
+    checkFutureStatusResponseNoTime(future, Status.OK);
+  }
+
+  protected void checkFutureStatusResponseNoTime(Future<Response> future,
+      Status status) throws Fault {
+    Response response = null;
+    try {
+      response = future.get();
+    } catch (Exception e) {
+      throw new Fault(e);
+    }
+    assertOkAndLog(response, status);
+  }
+
+  protected void checkFutureOkResponse(Future<Response> future) throws Fault {
+    checkMaxEndTime();
+    assertTrue(!future.isDone(), "Future cannot be done, yet!");
+    checkFutureOkResponseNoTime(future);
+  }
+
+  protected void checkFutureString(Future<String> future, String expectedValue)
+      throws Fault {
+    checkMaxEndTime();
+    assertTrue(!future.isDone(), "Future cannot be done, yet!");
+    String value = null;
+    try {
+      value = future.get();
+    } catch (Exception e) {
+      throw new Fault(e);
+    }
+    assertTrue(expectedValue.equalsIgnoreCase(value), "expected value"+
+        expectedValue+ "differes from acquired value"+ value);
+  }
+
+  protected void //
+      assertExceptionWithWebApplicationExceptionIsThrownAndLog(Future<?> future)
+          throws Fault {
+    try {
+      future.get();
+      throw new Fault("ExecutionException has not been thrown");
+    } catch (ExecutionException e) {
+      assertWebApplicationExceptionIsCauseAndLog(e);
+    } catch (InterruptedException e) {
+      throw new Fault("Unexpected exception thrown", e);
+    }
+  }
+
+  protected void assertExceptionWithProcessingExceptionIsThrownAndLog(
+      Future<?> future) throws Fault {
+    try {
+      future.get();
+      throw new Fault("ExecutionException has not been thrown");
+    } catch (ExecutionException e) {
+      assertProcessingExceptionIsCauseAndLog(e);
+    } catch (InterruptedException e) {
+      throw new Fault("Unexpected exception thrown", e);
+    }
+  }
+
+  protected void //
+      assertProcessingExceptionIsCauseAndLog(ExecutionException e)
+          throws Fault {
+    logMsg("ExecutionException has been thrown as expected", e);
+    assertTrue(hasWrapped(e, jakarta.ws.rs.ProcessingException.class),
+        "ExecutionException wrapped"+ e.getCause()+
+        "rather then ProcessingException");
+    logMsg("ExecutionException.getCause is ProcessingException as expected");
+  }
+
+  protected void //
+      assertWebApplicationExceptionIsCauseAndLog(ExecutionException e)
+          throws Fault {
+    logMsg("ExecutionException has been thrown as expected", e);
+    assertTrue(hasWrapped(e, WebApplicationException.class),
+        "ExecutionException wrapped"+ e.getCause()+
+        "rather then WebApplicationException");
+    logMsg(
+        "ExecutionException.getCause is WebApplicationException as expected");
+  }
+
+  static boolean //
+      hasWrapped(Throwable parent, Class<? extends Throwable> wrapped) {
+    while (parent.getCause() != null) {
+      if (wrapped.isInstance(parent.getCause()))
+        return true;
+      parent = parent.getCause();
+    }
+    return false;
+  }
+
+  protected void sleep(int millis) throws Fault {
+    try {
+      Thread.sleep(millis);
+    } catch (InterruptedException e) {
+      throw new Fault(e);
+    }
+  }
+
+  protected void setStartTime() {
+    millis = System.currentTimeMillis();
+    logMsg("Start time:", millis);
+  }
+
+  protected void checkMaxEndTime() throws Fault {
+    long endMillis = System.currentTimeMillis();
+    long diff = endMillis - millis;
+    logMsg("Client was returned control in", diff, "milliseconds from request");
+    assertTrue(diff <= Resource.SLEEP_TIME,
+        "AsyncInvoker was blocked waiting for a response");
+  }
+
+  protected void checkMinEndTime() throws Fault {
+    long endMillis = System.currentTimeMillis();
+    long diff = endMillis - millis;
+    logMsg("Callback#completed() called in", diff, "milliseconds from request");
+    assertTrue(diff >= Resource.SLEEP_TIME,
+        "AsyncInvoker.completed() was called unexpectedly soon, after"+ diff+
+        "milliseconds");
+  }
+
+  protected void assertCallbackCall() throws Fault {
+    while (callbackResult == 0) {
+      try {
+        Thread.sleep(100L);
+      } catch (InterruptedException e) {
+        throw new Fault(e);
+      }
+    }
+    switch (callbackResult) {
+    case 1:
+      logMsg("Callback completed() call ok");
+      break;
+    case 2:
+    case 3:
+      logMsg("Callback completed() call failed with error");
+      throw new Fault("Callback call failed with error", callbackException);
+    }
+    callbackResult = 0;
+  }
+
+  protected <T> GenericType<T> createGeneric(Class<T> clazz) {
+    return new GenericType<T>(clazz);
+  }
+
+  /**
+   * @param check
+   *          defines whether the test actually cares about methods
+   *          {@link InvocationCallback#completed(Object)} and
+   *          {@link InvocationCallback#failed(Throwable)} being called
+   * @return
+   */
+  protected InvocationCallback<Response> createCallback(boolean check) {
+    InvocationCallback<Response> callback = new Callback<Response>(check) {
+      @Override
+      public void completed(Response response) {
+        checkEndTime();
+      }
+    };
+    return callback;
+  }
+
+  protected InvocationCallback<String> createStringCallback(boolean check) {
+    InvocationCallback<String> callback = new Callback<String>(check) {
+      @Override
+      public void completed(String response) {
+        checkEndTime();
+      }
+    };
+    return callback;
+  }
+
+  abstract class Callback<RESPONSE> implements InvocationCallback<RESPONSE> {
+    protected boolean check;
+
+    public Callback(boolean check) {
+      this.check = check;
+    }
+
+    protected void checkEndTime() {
+      if (check)
+        try {
+          JAXRSClientIT.this.checkMinEndTime();
+          callbackResult = 1;
+        } catch (Fault e) {
+          callbackResult = 2;
+          callbackException = e;
+          throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void failed(Throwable throwable) {
+      if (check) {
+        callbackResult = 3;
+        callbackException = throwable;
+        throw new RuntimeException(throwable);
+      }
+    }
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/client/asyncinvoker/Resource.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/client/asyncinvoker/Resource.java
new file mode 100644
index 0000000..e761d04
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/client/asyncinvoker/Resource.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.ee.rs.client.asyncinvoker;
+
+import jakarta.ws.rs.tck.common.impl.TRACE;
+
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.HEAD;
+import jakarta.ws.rs.OPTIONS;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.Response.Status;
+
+@Path("resource")
+public class Resource {
+
+  public static final long SLEEP_TIME = 2000L;
+
+  @GET
+  @Path("get")
+  public String get() {
+    return "get";
+  }
+
+  @GET
+  @Path("getandwait")
+  public String getAndWait() throws InterruptedException {
+    Thread.sleep(SLEEP_TIME);
+    return "get";
+  }
+
+  @GET
+  @Path("getnotok")
+  public Response getReturnsStatusNotOk() {
+    return Response.status(Status.NOT_ACCEPTABLE).build();
+  }
+
+  @HEAD
+  @Path("head")
+  public String head() {
+    return "head";
+  }
+
+  @HEAD
+  @Path("headandwait")
+  public String headAndWait() throws InterruptedException {
+    Thread.sleep(SLEEP_TIME);
+    return "head";
+  }
+
+  @HEAD
+  @Path("headnotok")
+  public Response headReturnsStatusNotOk() {
+    return Response.status(Status.NOT_ACCEPTABLE).build();
+  }
+
+  @PUT
+  @Path("put")
+  public String put(String value) {
+    return value;
+  }
+
+  @PUT
+  @Path("putandwait")
+  public String putAndWait(String value) throws InterruptedException {
+    Thread.sleep(SLEEP_TIME);
+    return value;
+  }
+
+  @PUT
+  @Path("putnotok")
+  public Response putReturnsStatusNotOk(String value) {
+    return Response.status(Status.NOT_ACCEPTABLE).build();
+  }
+
+  @POST
+  @Path("post")
+  public String post(String value) {
+    return value;
+  }
+
+  @POST
+  @Path("postandwait")
+  public String postAndWait(String value) throws InterruptedException {
+    Thread.sleep(SLEEP_TIME);
+    return value;
+  }
+
+  @POST
+  @Path("postnotok")
+  public Response postReturnsStatusNotOk(String string) {
+    return Response.status(Status.NOT_ACCEPTABLE).build();
+  }
+
+  @DELETE
+  @Path("delete")
+  public String delete() {
+    return "delete";
+  }
+
+  @DELETE
+  @Path("deleteandwait")
+  public String deleteAndWait() throws InterruptedException {
+    Thread.sleep(SLEEP_TIME);
+    return "delete";
+  }
+
+  @DELETE
+  @Path("deletenotok")
+  public Response deleteReturnsStatusNotOk() {
+    return Response.status(Status.NOT_ACCEPTABLE).build();
+  }
+
+  @OPTIONS
+  @Path("options")
+  public String options() {
+    return "options";
+  }
+
+  @OPTIONS
+  @Path("optionsandwait")
+  public String optionsAndWait() throws InterruptedException {
+    Thread.sleep(SLEEP_TIME);
+    return "options";
+  }
+
+  @OPTIONS
+  @Path("optionsnotok")
+  public Response optionsReturnsStatusNotOk() {
+    return Response.status(Status.NOT_ACCEPTABLE).build();
+  }
+
+  @TRACE
+  @Path("trace")
+  public String trace() {
+    return "trace";
+  }
+
+  @TRACE
+  @Path("tracenotok")
+  public Response traceReturnsStatusNotOk() {
+    return Response.status(Status.NOT_ACCEPTABLE).build();
+  }
+
+  @TRACE
+  @Path("traceandwait")
+  public String traceAndWait() throws InterruptedException {
+    Thread.sleep(SLEEP_TIME);
+    return trace();
+  }
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/client/asyncinvoker/TSAppConfig.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/client/asyncinvoker/TSAppConfig.java
new file mode 100644
index 0000000..9dd436c
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/client/asyncinvoker/TSAppConfig.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.ee.rs.client.asyncinvoker;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import jakarta.ws.rs.core.Application;
+
+public class TSAppConfig extends Application {
+
+  public java.util.Set<java.lang.Class<?>> getClasses() {
+    Set<Class<?>> resources = new HashSet<Class<?>>();
+    resources.add(Resource.class);
+    return resources;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/core/request/JAXRSClientIT.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/core/request/JAXRSClientIT.java
new file mode 100644
index 0000000..c61353c
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/core/request/JAXRSClientIT.java
@@ -0,0 +1,539 @@
+/*
+ * Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.ee.rs.core.request;
+
+import org.apache.commons.httpclient.Header;
+import java.util.Properties;
+import java.io.InputStream;
+import java.io.IOException;
+import jakarta.ws.rs.tck.common.webclient.http.HttpResponse;
+import jakarta.ws.rs.tck.common.JAXRSCommonClient;
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+
+import org.jboss.arquillian.junit5.ArquillianExtension;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.jboss.shrinkwrap.api.exporter.ZipExporter;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.AfterEach;
+
+import jakarta.ws.rs.core.Response.Status;
+
+@ExtendWith(ArquillianExtension.class)
+public class JAXRSClientIT extends JAXRSCommonClient {
+
+  private static final long serialVersionUID = 1L;
+
+  private static final String IF_MODIFIED_SINCE = "If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT";
+
+  private static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT";
+
+  private static final String IF_NONE_MATCH = "If-None-Match: \"AAA\"";
+
+  public JAXRSClientIT() {
+    setup();
+    setContextRoot("/jaxrs_ee_core_request_web/RequestTest");
+  }
+
+
+  @Deployment(testable = false)
+  public static WebArchive createDeployment() throws IOException{
+
+    InputStream inStream = JAXRSClientIT.class.getClassLoader().getResourceAsStream("jakarta/ws/rs/tck/ee/rs/core/request/web.xml.template");
+    // Replace the servlet_adaptor in web.xml.template with the System variable set as servlet adaptor
+    String webXml = editWebXmlString(inStream);
+
+    WebArchive archive = ShrinkWrap.create(WebArchive.class, "jaxrs_ee_core_request_web.war");
+    archive.addClasses(TSAppConfig.class, RequestTest.class);
+    archive.setWebXML(new StringAsset(webXml));
+    //archive.addAsWebInfResource(JAXRSClientIT.class.getPackage(), "web.xml.template", "web.xml"); //can use if the web.xml.template doesn't need to be modified.    
+    return archive;
+
+  }
+
+  @BeforeEach
+  void logStartTest(TestInfo testInfo) {
+    TestUtil.logMsg("STARTING TEST : "+testInfo.getDisplayName());
+  }
+
+  @AfterEach
+  void logFinishTest(TestInfo testInfo) {
+    TestUtil.logMsg("FINISHED TEST : "+testInfo.getDisplayName());
+  }
+
+
+  /*
+   * @testName: getMethodGetRequestTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:118; JAXRS:SPEC:40;
+   * 
+   * @test_Strategy: Client send request to a resource, verify that
+   * Request.getMethod works.
+   */
+  @Test
+  public void getMethodGetRequestTest() throws Fault {
+    setProperty(REQUEST, buildRequest(GET, "GetMethodGetTest"));
+    setProperty(SEARCH_STRING, "PASSED");
+    invoke();
+  }
+
+  /*
+   * @testName: getMethodPutRequestTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:118;
+   * 
+   * @test_Strategy: Client send request to a resource, verify that
+   * Request.getMethod works.
+   */
+  @Test
+  public void getMethodPutRequestTest() throws Fault {
+    setProperty(REQUEST, buildRequest("PUT", "GetMethodPutTest"));
+    setProperty(SEARCH_STRING, "PASSED");
+    invoke();
+  }
+
+  /*
+   * @testName: getMethodPostRequestTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:118;
+   * 
+   * @test_Strategy: Client send request to a resource, verify that
+   * Request.getMethod works.
+   */
+  @Test
+  public void getMethodPostRequestTest() throws Fault {
+    setProperty(REQUEST, buildRequest("POST", "GetMethodPostTest"));
+    setProperty(SEARCH_STRING, "PASSED");
+    invoke();
+  }
+
+  /*
+   * @testName: getMethodDeleteRequestTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:118;
+   * 
+   * @test_Strategy: Client send request to a resource, verify that
+   * Request.getMethod works.
+   */
+  @Test
+  public void getMethodDeleteRequestTest() throws Fault {
+    setProperty(REQUEST, buildRequest("DELETE", "GetMethodDeleteTest"));
+    setProperty(SEARCH_STRING, "PASSED");
+    invoke();
+  }
+
+  /*
+   * @testName: getMethodHeadRequestTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:118;
+   * 
+   * @test_Strategy: Client send request to a resource, verify that
+   * Request.getMethod works.
+   */
+  @Test
+  public void getMethodHeadRequestTest() throws Fault {
+    setProperty(REQUEST, buildRequest("HEAD", "GetMethodHeadTest"));
+    setProperty(STATUS_CODE, getStatusCode(Status.OK));
+    invoke();
+  }
+
+  /*
+   * @testName: selectVariantGetRequestTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:119;
+   * 
+   * @test_Strategy: Client send request to a resource, verify that
+   * Request.selectVariantTest(List vs) works when vs is null.
+   */
+  @Test
+  public void selectVariantGetRequestTest() throws Fault {
+    setProperty(REQUEST, buildRequest(GET, "SelectVariantTestGet"));
+    setProperty(SEARCH_STRING, "PASSED");
+    invoke();
+  }
+
+  /*
+   * @testName: selectVariantPutRequestTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:119;
+   * 
+   * @test_Strategy: Client send request to a resource, verify that
+   * Request.selectVariantTest(List vs) works when vs is null.
+   */
+  @Test
+  public void selectVariantPutRequestTest() throws Fault {
+    setProperty(REQUEST, buildRequest("PUT", "SelectVariantTestPut"));
+    setProperty(SEARCH_STRING, "PASSED");
+    invoke();
+  }
+
+  /*
+   * @testName: selectVariantPostRequestTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:119;
+   * 
+   * @test_Strategy: Client send request to a resource, verify that
+   * Request.selectVariantTest(List vs) works when vs is null.
+   */
+  @Test
+  public void selectVariantPostRequestTest() throws Fault {
+    setProperty(REQUEST, buildRequest("POST", "SelectVariantTestPost"));
+    setProperty(Property.CONTENT, "POST");
+    setProperty(SEARCH_STRING, "PASSED");
+    invoke();
+  }
+
+  /*
+   * @testName: selectVariantDeleteRequestTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:119;
+   * 
+   * @test_Strategy: Client send request to a resource, verify that
+   * Request.selectVariantTest(List vs) works when vs is null.
+   */
+  @Test
+  public void selectVariantDeleteRequestTest() throws Fault {
+    setProperty(REQUEST, buildRequest("DELETE", "SelectVariantTestDelete"));
+    setProperty(SEARCH_STRING, "PASSED");
+    invoke();
+  }
+
+  /*
+   * @testName: selectVariantResponseVaryTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:119; JAXRS:SPEC:40;
+   * 
+   * @test_Strategy: Check if the response contains VARY
+   */
+  @Test
+  public void selectVariantResponseVaryTest() throws Fault {
+    setProperty(Property.REQUEST,
+        buildRequest(GET, "SelectVariantTestResponse"));
+    setProperty(Property.REQUEST_HEADERS, "Accept: application/json");
+    setProperty(Property.REQUEST_HEADERS, "Accept-Encoding: *");
+    setProperty(Property.REQUEST_HEADERS, "Accept-Language: *");
+    setProperty(Property.STATUS_CODE, getStatusCode(Status.OK));
+    invoke();
+
+    HttpResponse response = _testCase.getResponse();
+    Header[] headers = response.getResponseHeaders("Vary");
+    assertTrue(headers.length != 0, "Expected at least 1 Vary response header");
+
+    boolean accept = false, lang = false, encoding = false;
+    for (Header header : headers)
+      for (String vary : header.getValue().split(",")) {
+        lang |= vary.contains("Accept-Language");
+        encoding |= vary.contains("Accept-Encoding");
+        accept |= (vary.contains("Accept") && !vary.contains("Accept-"));
+      }
+    assertTrue(lang, "Vary should contain Accept-Language");
+    assertTrue(encoding, "Vary should contain Accept-Encoding");
+    assertTrue(accept, "Vary should contain Accept");
+  }
+
+  /*
+   * @testName: evaluatePreconditionsTagNullAndSimpleGetTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:115; JAXRS:SPEC:40;
+   * 
+   * @test_Strategy: Verify null and Simple Tag for GET
+   * 
+   */
+  @Test
+  public void evaluatePreconditionsTagNullAndSimpleGetTest() throws Fault {
+    setProperty(REQUEST, buildRequest(GET, "preconditionsSimpleGet"));
+    setProperty(STATUS_CODE, getStatusCode(Status.OK));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsEntityTagIfMatchAAAGetTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:115;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-Match: AAA Tag for GET
+   */
+  @Test
+  public void evaluatePreconditionsEntityTagIfMatchAAAGetTest() throws Fault {
+    setProperty(REQUEST, buildRequest(GET, "preconditionsAAAGet"));
+    setProperty(REQUEST_HEADERS, "If-Match: \"AAA\"");
+    setProperty(STATUS_CODE, getStatusCode(Status.OK));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsEntityTagIfMatchBBBGetTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:115;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-Match: BBB Tag for GET
+   */
+  @Test
+  public void evaluatePreconditionsEntityTagIfMatchBBBGetTest() throws Fault {
+    setProperty(REQUEST, buildRequest(GET, "preconditionsAAAGet"));
+    setProperty(REQUEST_HEADERS, "If-Match: \"BBB\"");
+    setProperty(STATUS_CODE, getStatusCode(Status.PRECONDITION_FAILED));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsEntityTagIfMatchAAAPutTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:115;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-Match: AAA Tag for PUT
+   */
+  @Test
+  public void evaluatePreconditionsEntityTagIfMatchAAAPutTest() throws Fault {
+    setProperty(REQUEST, buildRequest("PUT", "preconditionsAAAPut"));
+    setProperty(REQUEST_HEADERS, "If-Match: \"AAA\"");
+    setProperty(STATUS_CODE, getStatusCode(Status.OK));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsEntityTagIfMatchBBBPutTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:115;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-Match: BBB Tag for PUT
+   */
+  @Test
+  public void evaluatePreconditionsEntityTagIfMatchBBBPutTest() throws Fault {
+    setProperty(REQUEST, buildRequest("PUT", "preconditionsAAAPut"));
+    setProperty(REQUEST_HEADERS, "If-Match: \"BBB\"");
+    setProperty(STATUS_CODE, getStatusCode(Status.PRECONDITION_FAILED));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsTagIfNonMatchAAAGetTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:115;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-None-Match: AAA Tag for
+   * GET
+   */
+  @Test
+  public void evaluatePreconditionsTagIfNonMatchAAAGetTest() throws Fault {
+    setProperty(REQUEST, buildRequest(GET, "preconditionsAAAGet"));
+    setProperty(REQUEST_HEADERS, IF_NONE_MATCH);
+    setProperty(STATUS_CODE, getStatusCode(Status.PRECONDITION_FAILED));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsTagIfNonMatchAAAPutTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:115;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-None-Match: AAA Tag for
+   * PUT
+   */
+  @Test
+  public void evaluatePreconditionsTagIfNonMatchAAAPutTest() throws Fault {
+    setProperty(REQUEST, buildRequest("PUT", "preconditionsAAAPut"));
+    setProperty(REQUEST_HEADERS, IF_NONE_MATCH);
+    setProperty(STATUS_CODE, getStatusCode(Status.PRECONDITION_FAILED));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsTagIfNonMatchGetTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:298;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-None-Match No Tag for
+   * GET
+   */
+  @Test
+  public void evaluatePreconditionsTagIfNonMatchGetTest() throws Fault {
+    setProperty(REQUEST, buildRequest(GET, "preconditionsGet"));
+    setProperty(REQUEST_HEADERS, IF_NONE_MATCH);
+    setProperty(STATUS_CODE, getStatusCode(Status.OK));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsTagIfNonMatchAAAHeadTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:115;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-None-Match: AAA Tag for
+   * HEAD
+   */
+  @Test
+  public void evaluatePreconditionsTagIfNonMatchAAAHeadTest() throws Fault {
+    setProperty(REQUEST, buildRequest("HEAD", "preconditionsAAAHead"));
+    setProperty(REQUEST_HEADERS, IF_NONE_MATCH);
+    setProperty(STATUS_CODE, getStatusCode(Status.PRECONDITION_FAILED));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsIfNonMatchHeadTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:298;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-None-Match No Tag for
+   * HEAD
+   */
+  @Test
+  public void evaluatePreconditionsIfNonMatchHeadTest() throws Fault {
+    setProperty(REQUEST, buildRequest("HEAD", "preconditionsHead"));
+    setProperty(REQUEST_HEADERS, IF_NONE_MATCH);
+    setProperty(STATUS_CODE, getStatusCode(Status.OK));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsIfModSinceAgesAgoGetTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:116;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-Modified-Since, but was
+   * not modified for GET
+   */
+  @Test
+  public void evaluatePreconditionsIfModSinceAgesAgoGetTest() throws Fault {
+    setProperty(REQUEST, buildRequest(GET, "preconditionsAgesAgoGet"));
+    setProperty(REQUEST_HEADERS, IF_MODIFIED_SINCE);
+    setProperty(STATUS_CODE, getStatusCode(Status.PRECONDITION_FAILED));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsIfUnmodSinceAgesAgoGetTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:116;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-Unmodified-Since, but
+   * was not modified for GET
+   */
+  @Test
+  public void evaluatePreconditionsIfUnmodSinceAgesAgoGetTest() throws Fault {
+    setProperty(REQUEST, buildRequest(GET, "preconditionsAgesAgoGet"));
+    setProperty(REQUEST_HEADERS, IF_UNMODIFIED_SINCE);
+    setProperty(STATUS_CODE, getStatusCode(Status.OK));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsIfModSinceNowGetTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:116;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-Modified-Since for GET,
+   * was modified
+   */
+  @Test
+  public void evaluatePreconditionsIfModSinceNowGetTest() throws Fault {
+    setProperty(REQUEST, buildRequest(GET, "preconditionsNowGet"));
+    setProperty(REQUEST_HEADERS, IF_MODIFIED_SINCE);
+    setProperty(STATUS_CODE, getStatusCode(Status.OK));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsIfUnmodSinceNowGetTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:116;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-Modified-Since for GET,
+   * was modified
+   */
+  @Test
+  public void evaluatePreconditionsIfUnmodSinceNowGetTest() throws Fault {
+    setProperty(REQUEST, buildRequest(GET, "preconditionsNowGet"));
+    setProperty(REQUEST_HEADERS, IF_UNMODIFIED_SINCE);
+    setProperty(STATUS_CODE, getStatusCode(Status.PRECONDITION_FAILED));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsTagIfModAAASinceGetTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:117;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-Modified-Since, but was
+   * not modified for GET
+   */
+  @Test
+  public void evaluatePreconditionsTagIfModAAASinceGetTest() throws Fault {
+    setProperty(REQUEST, buildRequest(GET, "preconditionsAAAAgesAgoGet"));
+    setProperty(REQUEST_HEADERS, IF_MODIFIED_SINCE);
+    setProperty(STATUS_CODE, getStatusCode(Status.PRECONDITION_FAILED));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsTagIfUnmodSinceAAAGetTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:117;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-Unmodified-Since, but
+   * was not modified for GET
+   */
+  @Test
+  public void evaluatePreconditionsTagIfUnmodSinceAAAGetTest() throws Fault {
+    setProperty(REQUEST, buildRequest(GET, "preconditionsAAAAgesAgoGet"));
+    setProperty(REQUEST_HEADERS, IF_UNMODIFIED_SINCE);
+    setProperty(STATUS_CODE, getStatusCode(Status.OK));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsTagIfModSinceNowAAAGetTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:117;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-Modified-Since for GET,
+   * was modified
+   */
+  @Test
+  public void evaluatePreconditionsTagIfModSinceNowAAAGetTest() throws Fault {
+    setProperty(REQUEST, buildRequest(GET, "preconditionsNowAAAGet"));
+    setProperty(REQUEST_HEADERS, IF_MODIFIED_SINCE);
+    setProperty(STATUS_CODE, getStatusCode(Status.OK));
+    invoke();
+  }
+
+  /*
+   * @testName: evaluatePreconditionsTagIfUnmodSinceNowAAAGetTest
+   * 
+   * @assertion_ids: JAXRS:JAVADOC:117;
+   * 
+   * @test_Strategy: Verify evaluatePreconditions for If-Modified-Since for GET,
+   * was modified
+   */
+  @Test
+  public void evaluatePreconditionsTagIfUnmodSinceNowAAAGetTest() throws Fault {
+    setProperty(REQUEST, buildRequest(GET, "preconditionsNowAAAGet"));
+    setProperty(REQUEST_HEADERS, IF_UNMODIFIED_SINCE);
+    setProperty(STATUS_CODE, getStatusCode(Status.PRECONDITION_FAILED));
+    invoke();
+  }
+
+}
\ No newline at end of file
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/core/request/RequestTest.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/core/request/RequestTest.java
new file mode 100644
index 0000000..f503c40
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/core/request/RequestTest.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.ee.rs.core.request;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.HEAD;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.EntityTag;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Request;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.Response.ResponseBuilder;
+import jakarta.ws.rs.core.Response.Status;
+import jakarta.ws.rs.core.Variant;
+
+@Path(value = "/RequestTest")
+public class RequestTest {
+
+  // ------------------ GET METHOD ----------------------------
+
+  private static Response assertResponse(String expectedMethod,
+      String actualMethod) {
+    if (actualMethod.equalsIgnoreCase(expectedMethod)) {
+      return Response.ok("Test PASSED").build();
+    } else {
+      return Response.ok("Test FAILED with " + actualMethod).build();
+    }
+  }
+
+  @GET
+  @Path("/GetMethodGetTest")
+  public Response getTest(@Context Request req) {
+    String method = req.getMethod();
+    return assertResponse("GET", method);
+  }
+
+  @PUT
+  @Path("/GetMethodPutTest")
+  public Response putTest(@Context Request req) {
+    String method = req.getMethod();
+    return assertResponse("PUT", method);
+  }
+
+  @POST
+  @Path("/GetMethodPostTest")
+  public Response postTest(@Context Request req) {
+    String method = req.getMethod();
+    return assertResponse("POST", method);
+  }
+
+  @DELETE
+  @Path("/GetMethodDeleteTest")
+  public Response deleteTest(@Context Request req) {
+    String method = req.getMethod();
+    return assertResponse("DELETE", method);
+  }
+
+  @HEAD
+  @Path("/GetMethodHeadTest")
+  public Response headTest(@Context Request req) {
+    String method = req.getMethod();
+
+    if (method.equalsIgnoreCase("HEAD")) {
+      return Response.ok().build();
+    } else {
+      return Response.status(400).build();
+    }
+  }
+
+  // ------------------ SELECT VARIANT ----------------------------
+
+  @GET
+  @Path("/SelectVariantTestGet")
+  public Response selectVariantTestGet(@Context Request req) {
+    List<Variant> vs = null;
+
+    try {
+      req.selectVariant(vs);
+      return Response.ok("Test FAILED - no exception thrown").build();
+    } catch (IllegalArgumentException ile) {
+      return Response.ok("Test PASSED - expected exception thrown").build();
+    } catch (Throwable th) {
+      return Response
+          .ok("Test FAILED - wrong type exception thrown" + th.getMessage())
+          .build();
+    }
+  }
+
+  @PUT
+  @Path("/SelectVariantTestPut")
+  public Response selectVariantTestPut(@Context Request req) {
+    return selectVariantTestGet(req);
+  }
+
+  @POST
+  @Path("/SelectVariantTestPost")
+  public Response selectVariantTestPost(@Context Request req) {
+    return selectVariantTestGet(req);
+  }
+
+  @DELETE
+  @Path("/SelectVariantTestDelete")
+  public Response selectVariantTestDelete(@Context Request req) {
+    return selectVariantTestGet(req);
+  }
+
+  @GET
+  @Path("/SelectVariantTestResponse")
+  public Response selectVariantTestResponse(@Context Request req) {
+    List<Variant> list = Variant.encodings("CP1250", "UTF-8")
+        .languages(Locale.ENGLISH).mediaTypes(MediaType.APPLICATION_JSON_TYPE)
+        .add().build();
+    Variant selectedVariant = req.selectVariant(list);
+    if (null == selectedVariant)
+      return Response.notAcceptable(list).build();
+    return Response.ok("entity").build();
+  }
+
+  // ------------------ EVALUATE PRECONDITIONS ----------------------------
+  private static boolean evaluatePreconditionsEntityTagNull(Request req) {
+    try {
+      req.evaluatePreconditions((EntityTag) null);
+      return false;
+    } catch (IllegalArgumentException iae) {
+      return true;
+    }
+  }
+
+  private static boolean evaluatePreconditionsNowEntityTagNull(Request req) {
+    try {
+      Date now = Calendar.getInstance().getTime();
+      req.evaluatePreconditions(now, (EntityTag) null);
+      return false;
+    } catch (IllegalArgumentException iae) {
+      return true;
+    }
+  }
+
+  private static boolean evaluatePreconditionsDateEntityTag(Request req,
+      Date date, String tag) {
+    ResponseBuilder rb = req.evaluatePreconditions(date, createTag(tag));
+    return rb == null;
+  }
+
+  private static boolean evaluatePreconditionsDate(Request req, Date date) {
+    ResponseBuilder rb = req.evaluatePreconditions(date);
+    return rb == null;
+  }
+
+  private static boolean evaluatePreconditions(Request req) {
+    ResponseBuilder rb = req.evaluatePreconditions();
+    return rb == null;
+  }
+
+  private static EntityTag createTag(String tag) {
+    String xtag = new StringBuilder().append("\"").append(tag).append("\"")
+        .toString();
+    return EntityTag.valueOf(xtag);
+  }
+
+  private static boolean evaluatePreconditionsEntityTag(Request req,
+      String tag) {
+    ResponseBuilder rb = req.evaluatePreconditions(createTag(tag));
+    return rb == null;
+  }
+
+  private static Response createResponse(boolean ok) {
+    Status status = ok ? Status.OK : Status.PRECONDITION_FAILED;
+    return Response.status(status).build();
+  }
+
+  private static Date getYear1900() {
+    Calendar calendar = Calendar.getInstance();
+    calendar.set(Calendar.YEAR, 1900);
+    return calendar.getTime();
+  }
+
+  @GET
+  @Path("/preconditionsSimpleGet")
+  public Response evaluatePreconditionsEntityTagGetSimpleTest(
+      @Context Request req) {
+    boolean ok = evaluatePreconditionsEntityTag(req, "AAA");
+    if (!ok)
+      return Response.status(Status.GONE).build();
+    ok &= evaluatePreconditionsNowEntityTagNull(req);
+    if (!ok)
+      return Response.status(Status.NOT_ACCEPTABLE).build();
+    ok &= evaluatePreconditionsEntityTagNull(req);
+    return createResponse(ok);
+  }
+
+  @GET
+  @Path("/preconditionsAAAGet")
+  public Response evaluatePreconditionsEntityTagAAAGetTest(
+      @Context Request req) {
+    boolean ok = evaluatePreconditionsEntityTag(req, "AAA");
+    return createResponse(ok);
+  }
+
+  @PUT
+  @Path("/preconditionsAAAPut")
+  public Response evaluatePreconditionsEntityTagAAAPutTest(
+      @Context Request req) {
+    return evaluatePreconditionsEntityTagAAAGetTest(req);
+  }
+
+  @HEAD
+  @Path("/preconditionsAAAHead")
+  public Response evaluatePreconditionsEntityTagAAAHeadTest(
+      @Context Request req) {
+    return evaluatePreconditionsEntityTagAAAGetTest(req);
+  }
+
+  @GET
+  @Path("/preconditionsAAAAgesAgoGet")
+  public Response evaluatePreconditionsAgesAgoEntityTagAAAGetTest(
+      @Context Request req) {
+    Date date = getYear1900();
+    boolean ok = evaluatePreconditionsDateEntityTag(req, date, "AAA");
+    return createResponse(ok);
+  }
+
+  @GET
+  @Path("/preconditionsNowAAAGet")
+  public Response evaluatePreconditionsDateEntityTagAAAGetTest(
+      @Context Request req) {
+    Date date = Calendar.getInstance().getTime();
+    boolean ok = evaluatePreconditionsDateEntityTag(req, date, "AAA");
+    return createResponse(ok);
+  }
+
+  @GET
+  @Path("/preconditionsNowGet")
+  public Response evaluatePreconditionsDateGetTest(@Context Request req) {
+    Date date = Calendar.getInstance().getTime();
+    boolean ok = evaluatePreconditionsDate(req, date);
+    return createResponse(ok);
+  }
+
+  @GET
+  @Path("/preconditionsAgesAgoGet")
+  public Response evaluatePreconditionsAgesAgoGetTest(@Context Request req) {
+    Date date = getYear1900();
+    boolean ok = evaluatePreconditionsDate(req, date);
+    return createResponse(ok);
+  }
+
+  @GET
+  @Path("/preconditionsGet")
+  public Response evaluatePreconditionsGetTest(@Context Request req) {
+    boolean ok = evaluatePreconditions(req);
+    return createResponse(ok);
+  }
+
+  @GET
+  @Path("/preconditionsHead")
+  public Response evaluatePreconditionsHeadTest(@Context Request req) {
+    boolean ok = evaluatePreconditions(req);
+    return createResponse(ok);
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/core/request/TSAppConfig.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/core/request/TSAppConfig.java
new file mode 100644
index 0000000..a483d2a
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/ee/rs/core/request/TSAppConfig.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.ee.rs.core.request;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import jakarta.ws.rs.core.Application;
+
+public class TSAppConfig extends Application {
+
+  public java.util.Set<java.lang.Class<?>> getClasses() {
+    Set<Class<?>> resources = new HashSet<Class<?>>();
+    resources.add(RequestTest.class);
+    return resources;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/deliverable/PropertyManagerInterface.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/deliverable/PropertyManagerInterface.java
new file mode 100644
index 0000000..6d24903
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/deliverable/PropertyManagerInterface.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.lib.deliverable;
+
+import java.util.Properties;
+
+/**
+ * This class serves as a well known place for harness, util, and porting
+ * classes to retrieve property values.
+ *
+ * @author Kyle Grucci
+ */
+public interface PropertyManagerInterface {
+
+  /**
+   * This method swaps all of the following interop values in
+   * TSPropertyManager...
+   *
+   */
+  public void swapInteropPropertyValues(String sDirection);
+
+  /**
+   * gets a new properties containing all entries in the property manager. Any
+   * operation on the returned properties will have no effect on property
+   * manager
+   */
+  public Properties getJteProperties();
+
+  /**
+   * gets property value with default
+   *
+   * @param sKey - Property to retrieve
+   * @param default - default value to use
+   * @return String - property value
+   */
+  public String getProperty(String sKey, String def);
+
+  /**
+   * This method is called to get a property value
+   *
+   * @param sKey
+   *          - Property to retrieve
+   * @return String - property value
+   */
+  public String getProperty(String sKey) throws PropertyNotSetException;
+
+  /**
+   * This method is called to set a property on the property manager
+   *
+   * @param skey - key to be used
+   * @param sVal - value to use
+   */
+  public void setProperty(String sKey, String sVal);
+
+  /**
+   * This method is called by the test harness to retrieve all properties needed
+   * by a particular test.
+   *
+   * @param sPropKeys - Properties to retrieve
+   * @return Properties - property/value pairs
+   */
+  public Properties getTestSpecificProperties(String[] sPropKeys)
+      throws PropertyNotSetException;
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/deliverable/PropertyNotSetException.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/deliverable/PropertyNotSetException.java
new file mode 100644
index 0000000..2debdde
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/deliverable/PropertyNotSetException.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+ package jakarta.ws.rs.tck.lib.deliverable;
+
+public class PropertyNotSetException extends java.lang.Exception {
+  public PropertyNotSetException(String s) {
+    super(s);
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/implementation/sun/common/SunRIURL.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/implementation/sun/common/SunRIURL.java
new file mode 100644
index 0000000..e1956ca
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/implementation/sun/common/SunRIURL.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.lib.implementation.sun.common;
+
+import java.net.*;
+import jakarta.ws.rs.tck.lib.util.*;
+import jakarta.ws.rs.tck.lib.porting.*;
+
+/**
+ * This is a J2EE Reference specific implementation of the TSURLInterface which
+ * is to be used for J2EE-TS testing. TS tests use this interface to obtain the
+ * URL String to use to access a given web component. If a given J2EE Server
+ * implmentation requires that URLs be created in a different manner, then this
+ * implementation can be replaced.
+ *
+ * @author Kyle Grucci
+ */
+public class SunRIURL implements TSURLInterface {
+  private URL url = null;
+
+  /**
+   * This method is called by TS tests to get the URL to use to access a given
+   * web component.
+   *
+   * @param protocol
+   *          - the name of the protocol.
+   * @param host
+   *          - the name of the host.
+   * @param port
+   *          - the port number.
+   * @param file
+   *          - the host file.
+   * @return a valid URL object.
+   */
+  public URL getURL(String protocol, String host, int port, String file)
+      throws MalformedURLException {
+    try {
+      url = new URL(protocol, host, port, file);
+    } catch (MalformedURLException e) {
+      TestUtil.logErr("Failed during URL creation", e);
+      throw e;
+    }
+    return url;
+  }
+
+  /**
+   * This method is called by TS tests to get the URL to use to access a given
+   * web component.
+   *
+   * @param protocol
+   *          - the name of the protocol.
+   * @param host
+   *          - the name of the host.
+   * @param port
+   *          - the port number.
+   * @param file
+   *          - the host file.
+   * @return a valid URL as a String.
+   */
+  public String getURLString(String protocol, String host, int port,
+      String file) {
+    if (file.startsWith("/"))
+      return protocol + "://" + host + ":" + port + file;
+    else
+      return protocol + "://" + host + ":" + port + "/" + file;
+  }
+
+  /**
+   * This method is called by TS tests to get the request string to use to
+   * access a given web component.
+   *
+   * @param request
+   *          - the request file.
+   * @return a valid String object.
+   */
+  public String getRequest(String request) {
+    return request;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/implementation/sun/jersey/TSWebConfiguration.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/implementation/sun/jersey/TSWebConfiguration.java
new file mode 100644
index 0000000..2fd13d5
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/implementation/sun/jersey/TSWebConfiguration.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 2008, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+
+package jakarta.ws.rs.tck.lib.implementation.sun.jersey;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import jakarta.ws.rs.tck.lib.deliverable.PropertyManagerInterface;
+
+import jakarta.ws.rs.tck.lib.util.TestUtil;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * This is a utility class that borrowed from Kyle Grucci's original work in
+ * TSRuntimeConfiguration.java. It is called to replace any configurable
+ * properties in the web xml files with the implementation specific values
+ * specified in ts.jte. A copy is made of each web xml file (with the
+ * substituted values) in the same location with file extension .new.
+ *
+ * @author Dianne Jiao
+ */
+public class TSWebConfiguration {
+
+  // whether running with s1as or j2sdkee RI
+  private static Boolean runningS1AS;
+
+  public final static String WEB_XML = "web.xml.template";
+
+  private File tempFile;
+
+  private PrintWriter log;
+
+  private static Hashtable htReplacementProps = new Hashtable();
+
+  private Hashtable htReplacerTable = new Hashtable();
+
+  private static String sTempDir = "";
+
+  private StringReplacer replacer = new StringReplacer();
+
+  private static File jteFile = new File(System.getProperty("TS_HOME")
+      + File.separator + "bin" + File.separator + "ts.jte");
+
+  private static String servlet_adaptor = "servlet_adaptor";
+
+  private static String implementation_name = "jaxrs_impl_name";
+
+  private PropertyManagerInterface propMgr;
+
+  static Properties props;
+
+  static List<String> props_name = Arrays.asList("servlet_adaptor");
+
+  public TSWebConfiguration() {
+    System.out.println("Dummy TSWebConfiguration Conctructor");
+  }
+
+  public static void main(String[] args) {
+
+    TSWebConfiguration webconfig = new TSWebConfiguration();
+
+    implementation_name = webconfig.findProps(implementation_name);
+    System.out.println("++++++++++++=" + implementation_name);
+
+    servlet_adaptor = webconfig.findProps(servlet_adaptor);
+    servlet_adaptor = servlet_adaptor.replace(".class", "").replace("/", ".");
+    System.out
+        .println("Replacement value for servlet_adaptor =" + servlet_adaptor);
+
+    PrintWriter logOut = new PrintWriter(System.out, true);
+
+    File fileList = new File(System.getProperty("TS_HOME") + File.separator
+        + "bin" + File.separator + "jaxrs_filelist");
+
+    try {
+      BufferedReader input = new BufferedReader(new FileReader(fileList));
+
+      try {
+        String line = null; // not declared within while loop
+        while ((line = input.readLine()) != null) {
+          System.out.println("Processing file " + line);
+          File file = new File(
+              System.getProperty("TS_HOME") + File.separator + line);
+          try {
+            htReplacementProps.put("servlet_adaptor", servlet_adaptor);
+            webconfig.sweepwebFile(file);
+            System.out.println("Done with file " + file.toString());
+          } catch (Exception e) {
+            e.printStackTrace();
+            System.out
+                .println("Failed to modify xml files with correct settings.  "
+                    + "Please check the values of");
+          }
+        }
+      } finally {
+        input.close();
+      }
+    } catch (IOException ex) {
+      ex.printStackTrace();
+    }
+    System.exit(0);
+  }
+
+  String findProps(String prop) {
+    System.out.println("Processing jte file");
+    String replace = null;
+
+    try {
+      BufferedReader input = new BufferedReader(new FileReader(jteFile));
+
+      try {
+        String line = null;
+        while ((line = input.readLine()) != null) {
+          if (line.startsWith(prop)) {
+            replace = line.split("=")[1];
+            return replace;
+          }
+        }
+      } finally {
+        input.close();
+      }
+    } catch (IOException ex) {
+      ex.printStackTrace();
+    }
+    return null;
+  }
+
+  /// I am here now
+  public String sweepwebFile(File file)
+      throws FileNotFoundException, IOException {
+    if (htReplacerTable != null && !(htReplacerTable.isEmpty())) {
+      htReplacerTable = replaceOnWebInfoStrings(htReplacerTable);
+    }
+    String dir = file.getParent();
+    File xml = new File(dir + File.separator + file.getName());
+
+    return replacer.replace(file, htReplacementProps, htReplacerTable, dir);
+  }
+
+  final class StringReplacer {
+
+    public String sFindString; // string we are searching for
+
+    public String sReplaceString; // replace sFindString with this
+
+    public String sDirString;
+
+    public String sFileNameStringToReplace;
+
+    public String sNewFileNameString;
+
+    public int iHowMany = -1;
+
+    public String[] sFileList;
+
+    public boolean bNewFile = false;
+
+    private Hashtable htFindAndReplace = null;
+
+    private Hashtable htCustomTable = null;
+
+    private Vector vInfoObjects = new Vector();
+
+    private Vector vMatchingInfoObjects = new Vector();
+
+    private Vector vNonMatchingInfoObjects = new Vector();
+
+    private boolean bSomethingWasReplaced = false;
+
+    public String replace(File file, Hashtable htStrings,
+        Hashtable htReplacerTable, String sTempDir) {
+      String[] sFileList = null;
+      htFindAndReplace = htStrings;
+      htCustomTable = htReplacerTable;
+      String sTemp = "";
+      ReplacementInfo ri = null;
+      String sNewFileName = "";
+      StringBuffer sFoundBuffer = new StringBuffer();
+      char c;
+      bSomethingWasReplaced = false;
+      BufferedReader fReader = null;
+      BufferedWriter fNewWriter = null;
+      try {
+        vInfoObjects = new Vector();
+        String sKey = "";
+        // create ReplacementInfo objects
+        for (Enumeration e = htFindAndReplace.keys(); e.hasMoreElements();) {
+          sKey = (String) e.nextElement();
+          vInfoObjects.addElement(
+              new ReplacementInfo(sKey, (String) htFindAndReplace.get(sKey)));
+        }
+        // add in the table the custom table of replacement strings
+        // if any
+        if (htCustomTable != null) {
+          for (Enumeration e = htCustomTable.keys(); e.hasMoreElements();) {
+            sKey = (String) e.nextElement();
+            vInfoObjects.addElement(
+                new ReplacementInfo(sKey, (String) htCustomTable.get(sKey)));
+
+          }
+        }
+        // reader of the file that we're searching
+        fReader = new BufferedReader(new FileReader(file));
+        System.out.println("File to read: " + file.getAbsolutePath());
+        StringWriter sWriter = new StringWriter();
+        // stores new file contents
+
+        // The following code is here to account for the fact that we
+        // have some properties to replace which are substrings of other
+        // properties. We need to be sure that we will be able to
+        // replace either. Thus, we check the char after certain props
+        // to see if they continue to match another property. If so,
+        // then we will replace with the longer property value
+        boolean bCheckForDot = false;
+        String sHold = "";
+        int iCharRead; // holds each char that we read
+        vMatchingInfoObjects.addAll(vInfoObjects);
+        while ((iCharRead = fReader.read()) != -1) {
+          c = (char) iCharRead;
+
+          if (bCheckForDot) {
+            if (c != '.') {
+              // hold the dot and let the old processing happen
+              sHold = new String((new Character(c)).toString());
+              System.out.println("sHold = " + sHold);
+            } else {
+              sFoundBuffer.append(c);
+              bCheckForDot = false;
+              continue;
+              // since there is no need to just check .
+            }
+          } else {
+            if (sHold != null) {
+              // just write the char that we were holding. This
+              // assumes that this char is not the beginning of a
+              // string we want to replace
+              sWriter.write(sHold);
+              sHold = null;
+            }
+
+            sFoundBuffer.append(c);
+          }
+
+          sTemp = new String(sFoundBuffer);
+
+          // get all ris that still match
+          for (Enumeration e = vMatchingInfoObjects.elements(); e
+              .hasMoreElements();) {
+
+            ri = (ReplacementInfo) e.nextElement();
+            if (ri.sFind.startsWith(sTemp)) {
+              if (ri.sFind.equals(sTemp)) {
+
+                // what if we have a substring of another string that
+                // we are searching for?
+
+                System.out.println(
+                    "REPLACER:MATCH found:  " + ri.sFind + " matches " + sTemp);
+                ri.foundOccurance();
+                bSomethingWasReplaced = true;
+                sWriter.write(ri.sReplace);
+                // reset sFoundBuffer
+                sFoundBuffer = new StringBuffer();
+                // reset matchers to all again
+                vMatchingInfoObjects.removeAllElements();
+                vMatchingInfoObjects.addAll(vInfoObjects);
+                break;
+              }
+            } else {
+              vNonMatchingInfoObjects.addElement(ri);
+              // the char that we just read causes our string not
+              // to match the string we're looking for. Write the
+              // old string to the new file and reset sFoundBuffer.
+              // this will never happen!!!
+            }
+          }
+          // remove all non-matching ri's
+          vMatchingInfoObjects.removeAll(vNonMatchingInfoObjects);
+          vNonMatchingInfoObjects.removeAllElements();
+          // reset everything if there are none left matching
+          if (vMatchingInfoObjects.isEmpty()) {
+            sWriter.write(sTemp);
+            sFoundBuffer = new StringBuffer();
+            vMatchingInfoObjects.removeAllElements();
+            vMatchingInfoObjects.addAll(vInfoObjects);
+          }
+        }
+        fReader.close();
+        if (bSomethingWasReplaced) {
+          sNewFileName = sTempDir + File.separator + "web.xml."
+              + implementation_name;
+          System.out.println("New filename:" + sNewFileName);
+          fNewWriter = new BufferedWriter(
+              new FileWriter(new File(sNewFileName)));
+          fNewWriter.write(sWriter.toString());
+          fNewWriter.flush();
+        } else {
+          sNewFileName = null;
+        }
+      } catch (Exception e) {
+        e.printStackTrace();
+      } finally {
+        if (fNewWriter != null) {
+          try {
+            fNewWriter.close();
+          } catch (IOException exp) {
+          }
+        }
+      }
+      return sNewFileName;
+    }
+
+    class ReplacementInfo {
+
+      private int iFoundOccurances = 0;
+
+      private String sFind = null;
+
+      private String sReplace = null;
+
+      ReplacementInfo(String sFindString, String sReplaceString) {
+        sFind = sFindString;
+        sReplace = sReplaceString;
+        iFoundOccurances = 0;
+      }
+
+      public void foundOccurance() {
+        iFoundOccurances++;
+        if (TestUtil.harnessDebug) {
+          System.out.println("we found an occurance #" + iFoundOccurances
+              + " of '" + sFind + "'");
+        }
+      }
+    }
+  }
+
+  /**
+   * Parse the HashTable which contains strings retrieved via calls into the
+   * porting classes for deployment. We must substitute on these strings prior
+   * to substituting them into the web.xml.
+   */
+  private Hashtable replaceOnWebInfoStrings(Hashtable extras) {
+
+    boolean changeIt = false;
+
+    String searchFor[] = { "servlet_adaptor" };
+
+    for (Enumeration e = extras.keys(); e.hasMoreElements();) {
+      String sKey = (String) e.nextElement();
+      String val = (String) extras.get(sKey);
+      String oldJndi = val;
+      changeIt = false;
+      String buff = null;
+      int startPos = 0;
+      for (int i = 0; i < searchFor.length; i++) {
+        System.out.println("\n###Searching for=" + searchFor[i]);
+        if ((startPos = val.lastIndexOf(searchFor[i])) != -1) {
+          changeIt = true;
+          String startBuff = val.substring(0, startPos);
+          buff = (String) htReplacementProps.get(searchFor[i]);
+          val = startBuff + buff
+              + val.substring(startPos + searchFor[i].length());
+        }
+      }
+      if (changeIt) {
+        extras.put((String) sKey, val);
+        System.out.println(
+            "\n###\nold webInfo Val=" + oldJndi + "\nNew webInfo Val = " + val);
+      }
+    }
+    return extras;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/porting/TSURL.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/porting/TSURL.java
new file mode 100644
index 0000000..3c12b5e
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/porting/TSURL.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.lib.porting;
+
+import java.net.*;
+import java.io.Serializable;
+import jakarta.ws.rs.tck.lib.util.*;
+
+/**
+ * This is a Java EE Reference specific implementation of the TSURLInterface
+ * which is to be used for Java EE TCK testing. TS tests use this interface to
+ * obtain the URL String to use to access a given web component. If a given Java
+ * EE Server implmentation requires that URLs be created in a different manner,
+ * then this implementation can be replaced.
+ *
+ * @author Kyle Grucci
+ */
+public class TSURL implements TSURLInterface, Serializable {
+  private TSURLInterface ctsURL = null;
+
+  private String sClass = "porting.ts.url.class.1";
+
+  public TSURL() {
+    // we'll initialize the impl when the individual method is called
+    // this constructor assumes sClass = "porting.ts.url.class.1".
+  }
+
+  public TSURL(String sClassName) {
+    sClass = sClassName;
+  }
+
+  /**
+   * This method is called by TS tests to get the URL to use to access a given
+   * web component.
+   *
+   * @param protocol
+   *          - the name of the protocol.
+   * @param host
+   *          - the name of the host.
+   * @param port
+   *          - the port number.
+   * @param file
+   *          - the host file.
+   * @return a valid URL object.
+   */
+  public URL getURL(String protocol, String host, int port, String file)
+      throws MalformedURLException {
+    if (ctsURL == null) {
+      try {
+        // create and initialize a new instance of TSURLInterface
+        Class c = Class.forName(System.getProperty(sClass, "jakarta.ws.rs.tck.lib.implementation.sun.common.SunRIURL"));
+        ctsURL = (TSURLInterface) c.newInstance();
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
+
+    return ctsURL.getURL(protocol, host, port, file);
+  }
+
+  /**
+   * This method is called by TS tests to get the URL to use to access a given
+   * web component.
+   *
+   * @param protocol
+   *          - the name of the protocol.
+   * @param host
+   *          - the name of the host.
+   * @param port
+   *          - the port number.
+   * @param file
+   *          - the host file.
+   * @return a valid URL as a String.
+   */
+  public String getURLString(String protocol, String host, int port,
+      String file) {
+    if (ctsURL == null) {
+      try {
+        // create and initialize a new instance of TSURLInterface
+        Class c = Class.forName(System.getProperty(sClass, "jakarta.ws.rs.tck.lib.implementation.sun.common.SunRIURL"));
+        ctsURL = (TSURLInterface) c.newInstance();
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
+    return ctsURL.getURLString(protocol, host, port, file);
+  }
+
+  /**
+   * This method is called by TS tests to get the request string to use to
+   * access a given web component.
+   *
+   * @param request
+   *          - the request file.
+   * @return a valid String object.
+   */
+  public String getRequest(String request) {
+    if (ctsURL == null) {
+      try {
+        // create and initialize a new instance of TSURLInterface
+        Class c = Class.forName(System.getProperty(sClass, "jakarta.ws.rs.tck.lib.implementation.sun.common.SunRIURL"));
+        ctsURL = (TSURLInterface) c.newInstance();
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
+    return ctsURL.getRequest(request);
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/porting/TSURLInterface.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/porting/TSURLInterface.java
new file mode 100644
index 0000000..ee00989
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/porting/TSURLInterface.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.lib.porting;
+
+import java.net.*;
+
+/**
+ * An implementation of the TSURLInterface is to be used for Java EE TCK
+ * testing. TS tests use this interface to obtain the URL String to use to
+ * access a given web component. If a given Java EE Server implmentation
+ * requires that URLs be created in a different manner, then this implementation
+ * can be replaced.
+ *
+ * @author Kyle Grucci
+ */
+public interface TSURLInterface {
+  /**
+   * This method is called by TS tests to get the URL to use to access a given
+   * web component.
+   *
+   * @param protocol
+   *          - the name of the protocol.
+   * @param host
+   *          - the name of the host.
+   * @param port
+   *          - the port number.
+   * @param file
+   *          - the host file.
+   * @return a valid URL object.
+   */
+  public URL getURL(String protocol, String host, int port, String file)
+      throws MalformedURLException;
+
+  /**
+   * This method is called by TS tests to get the URL to use to access a given
+   * web component.
+   *
+   * @param protocol
+   *          - the name of the protocol.
+   * @param host
+   *          - the name of the host.
+   * @param port
+   *          - the port number.
+   * @param file
+   *          - the host file.
+   * @return a valid URL as a String.
+   */
+  public String getURLString(String protocol, String host, int port,
+      String file);
+
+  /**
+   * This method is called by TS tests to get the request to use to access a
+   * given web component.
+   *
+   * @param request
+   *          - the request file.
+   * @return a valid String object.
+   */
+  public String getRequest(String request);
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/BASE64Decoder.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/BASE64Decoder.java
new file mode 100644
index 0000000..c66eff9
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/BASE64Decoder.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 1995, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.lib.util;
+
+import java.io.OutputStream;
+import java.io.PushbackInputStream;
+import java.io.PrintStream;
+
+/**
+ * This class implements a BASE64 Character decoder as specified in RFC1521.
+ *
+ * This RFC is part of the MIME specification which is published by the Internet
+ * Engineering Task Force (IETF). Unlike some other encoding schemes there is
+ * nothing in this encoding that tells the decoder where a buffer starts or
+ * stops, so to use it you will need to isolate your encoded data into a single
+ * chunk and then feed them this decoder. The simplest way to do that is to read
+ * all of the encoded data into a string and then use:
+ * 
+ * <pre>
+ * byte mydata[];
+ * BASE64Decoder base64 = new BASE64Decoder();
+ *
+ * mydata = base64.decodeBuffer(bufferString);
+ * </pre>
+ * 
+ * This will decode the String in <i>bufferString</i> and give you an array of
+ * bytes in the array <i>myData</i>.
+ *
+ * On errors, this class throws a CEFormatException with the following detail
+ * strings:
+ * 
+ * <pre>
+ * "BASE64Decoder: Not enough bytes for an atom."
+ * </pre>
+ *
+ * @author Chuck McManis
+ * @see CharacterEncoder
+ * @see BASE64Decoder
+ */
+
+public class BASE64Decoder extends CharacterDecoder {
+
+  /** This class has 4 bytes per atom */
+  protected int bytesPerAtom() {
+    return (4);
+  }
+
+  /** Any multiple of 4 will do, 72 might be common */
+  protected int bytesPerLine() {
+    return (72);
+  }
+
+  /**
+   * This character array provides the character to value map based on RFC1521.
+   */
+  private final static char pem_array[] = {
+      // 0 1 2 3 4 5 6 7
+      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0
+      'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 1
+      'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 2
+      'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 3
+      'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 4
+      'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 5
+      'w', 'x', 'y', 'z', '0', '1', '2', '3', // 6
+      '4', '5', '6', '7', '8', '9', '+', '/' // 7
+  };
+
+  private final static byte pem_convert_array[] = new byte[256];
+
+  static {
+    for (int i = 0; i < 255; i++) {
+      pem_convert_array[i] = -1;
+    }
+    for (int i = 0; i < pem_array.length; i++) {
+      pem_convert_array[pem_array[i]] = (byte) i;
+    }
+  }
+
+  byte decode_buffer[] = new byte[4];
+
+  /**
+   * Decode one BASE64 atom into 1, 2, or 3 bytes of data.
+   */
+  protected void decodeAtom(PushbackInputStream inStream,
+      OutputStream outStream, int rem) throws java.io.IOException {
+    int i;
+    byte a = -1, b = -1, c = -1, d = -1;
+
+    if (rem < 2) {
+      throw new CEFormatException(
+          "BASE64Decoder: Not enough bytes for an atom.");
+    }
+    do {
+      i = inStream.read();
+      if (i == -1) {
+        throw new CEStreamExhausted();
+      }
+    } while (i == '\n' || i == '\r');
+    decode_buffer[0] = (byte) i;
+
+    i = readFully(inStream, decode_buffer, 1, rem - 1);
+    if (i == -1) {
+      throw new CEStreamExhausted();
+    }
+
+    if (rem > 3 && decode_buffer[3] == '=') {
+      rem = 3;
+    }
+    if (rem > 2 && decode_buffer[2] == '=') {
+      rem = 2;
+    }
+    switch (rem) {
+    case 4:
+      d = pem_convert_array[decode_buffer[3] & 0xff];
+      // NOBREAK
+    case 3:
+      c = pem_convert_array[decode_buffer[2] & 0xff];
+      // NOBREAK
+    case 2:
+      b = pem_convert_array[decode_buffer[1] & 0xff];
+      a = pem_convert_array[decode_buffer[0] & 0xff];
+      break;
+    }
+
+    switch (rem) {
+    case 2:
+      outStream.write((byte) (((a << 2) & 0xfc) | ((b >>> 4) & 3)));
+      break;
+    case 3:
+      outStream.write((byte) (((a << 2) & 0xfc) | ((b >>> 4) & 3)));
+      outStream.write((byte) (((b << 4) & 0xf0) | ((c >>> 2) & 0xf)));
+      break;
+    case 4:
+      outStream.write((byte) (((a << 2) & 0xfc) | ((b >>> 4) & 3)));
+      outStream.write((byte) (((b << 4) & 0xf0) | ((c >>> 2) & 0xf)));
+      outStream.write((byte) (((c << 6) & 0xc0) | (d & 0x3f)));
+      break;
+    }
+    return;
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/BASE64Encoder.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/BASE64Encoder.java
new file mode 100644
index 0000000..dfd7032
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/BASE64Encoder.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2006, 2021 Oracle and/or its affiliates. All rights reserved.
+ * 
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.lib.util;
+
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.io.IOException;
+
+/**
+ * This class implements a BASE64 Character encoder as specified in RFC1521.
+ * This RFC is part of the MIME specification as published by the Internet
+ * Engineering Task Force (IETF). Unlike some other encoding schemes there is
+ * nothing in this encoding that indicates where a buffer starts or ends.
+ *
+ * This means that the encoded text will simply start with the first line of
+ * encoded text and end with the last line of encoded text.
+ *
+ * @version 1.23, 11/17/05
+ * @author Chuck McManis
+ * @see CharacterEncoder
+ * @see BASE64Decoder
+ */
+
+public class BASE64Encoder extends CharacterEncoder {
+
+  /** this class encodes three bytes per atom. */
+  protected int bytesPerAtom() {
+    return (3);
+  }
+
+  /**
+   * this class encodes 57 bytes per line. This results in a maximum of 57/3 * 4
+   * or 76 characters per output line. Not counting the line termination.
+   */
+  protected int bytesPerLine() {
+    return (57);
+  }
+
+  /** This array maps the characters to their 6 bit values */
+  private final static char pem_array[] = {
+      // 0 1 2 3 4 5 6 7
+      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0
+      'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 1
+      'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 2
+      'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 3
+      'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 4
+      'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 5
+      'w', 'x', 'y', 'z', '0', '1', '2', '3', // 6
+      '4', '5', '6', '7', '8', '9', '+', '/' // 7
+  };
+
+  /**
+   * encodeAtom - Take three bytes of input and encode it as 4 printable
+   * characters. Note that if the length in len is less than three is encodes
+   * either one or two '=' signs to indicate padding characters.
+   */
+  protected void encodeAtom(OutputStream outStream, byte data[], int offset,
+      int len) throws IOException {
+    byte a, b, c;
+
+    if (len == 1) {
+      a = data[offset];
+      b = 0;
+      c = 0;
+      outStream.write(pem_array[(a >>> 2) & 0x3F]);
+      outStream.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
+      outStream.write('=');
+      outStream.write('=');
+    } else if (len == 2) {
+      a = data[offset];
+      b = data[offset + 1];
+      c = 0;
+      outStream.write(pem_array[(a >>> 2) & 0x3F]);
+      outStream.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
+      outStream.write(pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
+      outStream.write('=');
+    } else {
+      a = data[offset];
+      b = data[offset + 1];
+      c = data[offset + 2];
+      outStream.write(pem_array[(a >>> 2) & 0x3F]);
+      outStream.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
+      outStream.write(pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
+      outStream.write(pem_array[c & 0x3F]);
+    }
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/CEFormatException.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/CEFormatException.java
new file mode 100644
index 0000000..0b2c0b0
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/CEFormatException.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 1995, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.lib.util;
+
+import java.io.IOException;
+
+public class CEFormatException extends IOException {
+  public CEFormatException(String s) {
+    super(s);
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/CEStreamExhausted.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/CEStreamExhausted.java
new file mode 100644
index 0000000..b935609
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/CEStreamExhausted.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 1995, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.lib.util;
+
+import java.io.IOException;
+
+/** This exception is thrown when EOF is reached */
+public class CEStreamExhausted extends IOException {
+};
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/CharacterDecoder.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/CharacterDecoder.java
new file mode 100644
index 0000000..8143a77
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/CharacterDecoder.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 1995, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.lib.util;
+
+import java.io.OutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * This class defines the decoding half of character encoders. A character
+ * decoder is an algorithim for transforming 8 bit binary data that has been
+ * encoded into text by a character encoder, back into original binary form.
+ *
+ * The character encoders, in general, have been structured around a central
+ * theme that binary data can be encoded into text that has the form:
+ *
+ * <pre>
+ *      [Buffer Prefix]
+ *      [Line Prefix][encoded data atoms][Line Suffix]
+ *      [Buffer Suffix]
+ * </pre>
+ *
+ * Of course in the simplest encoding schemes, the buffer has no distinct prefix
+ * of suffix, however all have some fixed relationship between the text in an
+ * 'atom' and the binary data itself.
+ *
+ * In the CharacterEncoder and CharacterDecoder classes, one complete chunk of
+ * data is referred to as a <i>buffer</i>. Encoded buffers are all text, and
+ * decoded buffers (sometimes just referred to as buffers) are binary octets.
+ *
+ * To create a custom decoder, you must, at a minimum, overide three abstract
+ * methods in this class.
+ * <DL>
+ * <DD>bytesPerAtom which tells the decoder how many bytes to expect from
+ * decodeAtom
+ * <DD>decodeAtom which decodes the bytes sent to it as text.
+ * <DD>bytesPerLine which tells the encoder the maximum number of bytes per
+ * line.
+ * </DL>
+ *
+ * In general, the character decoders return error in the form of a
+ * CEFormatException. The syntax of the detail string is
+ * 
+ * <pre>
+ *      DecoderClassName: Error message.
+ * </pre>
+ *
+ * Several useful decoders have already been written and are referenced in the
+ * See Also list below.
+ *
+ * @author Chuck McManis
+ * @see CEFormatException
+ * @see CharacterEncoder
+ * @see UCDecoder
+ * @see UUDecoder
+ * @see BASE64Decoder
+ */
+
+public abstract class CharacterDecoder {
+
+  /** Return the number of bytes per atom of decoding */
+  abstract protected int bytesPerAtom();
+
+  /** Return the maximum number of bytes that can be encoded per line */
+  abstract protected int bytesPerLine();
+
+  /** decode the beginning of the buffer, by default this is a NOP. */
+  protected void decodeBufferPrefix(PushbackInputStream aStream,
+      OutputStream bStream) throws IOException {
+  }
+
+  /** decode the buffer suffix, again by default it is a NOP. */
+  protected void decodeBufferSuffix(PushbackInputStream aStream,
+      OutputStream bStream) throws IOException {
+  }
+
+  /**
+   * This method should return, if it knows, the number of bytes that will be
+   * decoded. Many formats such as uuencoding provide this information. By
+   * default we return the maximum bytes that could have been encoded on the
+   * line.
+   */
+  protected int decodeLinePrefix(PushbackInputStream aStream,
+      OutputStream bStream) throws IOException {
+    return (bytesPerLine());
+  }
+
+  /**
+   * This method post processes the line, if there are error detection or
+   * correction codes in a line, they are generally processed by this method.
+   * The simplest version of this method looks for the (newline) character.
+   */
+  protected void decodeLineSuffix(PushbackInputStream aStream,
+      OutputStream bStream) throws IOException {
+  }
+
+  /**
+   * This method does an actual decode. It takes the decoded bytes and writes
+   * them to the OutputStream. The integer <i>l</i> tells the method how many
+   * bytes are required. This is always <= bytesPerAtom().
+   */
+  protected void decodeAtom(PushbackInputStream aStream, OutputStream bStream,
+      int l) throws IOException {
+    throw new CEStreamExhausted();
+  }
+
+  /**
+   * This method works around the bizarre semantics of BufferedInputStream's
+   * read method.
+   */
+  protected int readFully(InputStream in, byte buffer[], int offset, int len)
+      throws java.io.IOException {
+    for (int i = 0; i < len; i++) {
+      int q = in.read();
+      if (q == -1)
+        return ((i == 0) ? -1 : i);
+      buffer[i + offset] = (byte) q;
+    }
+    return len;
+  }
+
+  /**
+   * Decode the text from the InputStream and write the decoded octets to the
+   * OutputStream. This method runs until the stream is exhausted.
+   * 
+   * @exception CEFormatException
+   *              An error has occured while decoding
+   * @exception CEStreamExhausted
+   *              The input stream is unexpectedly out of data
+   */
+  public void decodeBuffer(InputStream aStream, OutputStream bStream)
+      throws IOException {
+    int i;
+    int totalBytes = 0;
+
+    PushbackInputStream ps = new PushbackInputStream(aStream);
+    decodeBufferPrefix(ps, bStream);
+    while (true) {
+      int length;
+
+      try {
+        length = decodeLinePrefix(ps, bStream);
+        for (i = 0; (i + bytesPerAtom()) < length; i += bytesPerAtom()) {
+          decodeAtom(ps, bStream, bytesPerAtom());
+          totalBytes += bytesPerAtom();
+        }
+        if ((i + bytesPerAtom()) == length) {
+          decodeAtom(ps, bStream, bytesPerAtom());
+          totalBytes += bytesPerAtom();
+        } else {
+          decodeAtom(ps, bStream, length - i);
+          totalBytes += (length - i);
+        }
+        decodeLineSuffix(ps, bStream);
+      } catch (CEStreamExhausted e) {
+        break;
+      }
+    }
+    decodeBufferSuffix(ps, bStream);
+  }
+
+  /**
+   * Alternate decode interface that takes a String containing the encoded
+   * buffer and returns a byte array containing the data.
+   * 
+   * @exception CEFormatException
+   *              An error has occured while decoding
+   */
+  public byte decodeBuffer(String inputString)[] throws IOException {
+    byte inputBuffer[] = new byte[inputString.length()];
+    ByteArrayInputStream inStream;
+    ByteArrayOutputStream outStream;
+
+    inputString.getBytes(0, inputString.length(), inputBuffer, 0);
+    inStream = new ByteArrayInputStream(inputBuffer);
+    outStream = new ByteArrayOutputStream();
+    decodeBuffer(inStream, outStream);
+    return (outStream.toByteArray());
+  }
+
+  /**
+   * Decode the contents of the inputstream into a buffer.
+   */
+  public byte decodeBuffer(InputStream in)[] throws IOException {
+    ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+    decodeBuffer(in, outStream);
+    return (outStream.toByteArray());
+  }
+
+  /**
+   * Decode the contents of the String into a ByteBuffer.
+   */
+  public ByteBuffer decodeBufferToByteBuffer(String inputString)
+      throws IOException {
+    return ByteBuffer.wrap(decodeBuffer(inputString));
+  }
+
+  /**
+   * Decode the contents of the inputStream into a ByteBuffer.
+   */
+  public ByteBuffer decodeBufferToByteBuffer(InputStream in)
+      throws IOException {
+    return ByteBuffer.wrap(decodeBuffer(in));
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/CharacterEncoder.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/CharacterEncoder.java
new file mode 100644
index 0000000..feb23b3
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/CharacterEncoder.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2006, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.ws.rs.tck.lib.util;
+
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.io.OutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * This class defines the encoding half of character encoders. A character
+ * encoder is an algorithim for transforming 8 bit binary data into text
+ * (generally 7 bit ASCII or 8 bit ISO-Latin-1 text) for transmition over text
+ * channels such as e-mail and network news.
+ *
+ * The character encoders have been structured around a central theme that, in
+ * general, the encoded text has the form:
+ *
+ * <pre>
+ *	[Buffer Prefix]
+ *	[Line Prefix][encoded data atoms][Line Suffix]
+ *	[Buffer Suffix]
+ * </pre>
+ *
+ * In the CharacterEncoder and CharacterDecoder classes, one complete chunk of
+ * data is referred to as a <i>buffer</i>. Encoded buffers are all text, and
+ * decoded buffers (sometimes just referred to as buffers) are binary octets.
+ *
+ * To create a custom encoder, you must, at a minimum, overide three abstract
+ * methods in this class.
+ * <DL>
+ * <DD>bytesPerAtom which tells the encoder how many bytes to send to encodeAtom
+ * <DD>encodeAtom which encodes the bytes sent to it as text.
+ * <DD>bytesPerLine which tells the encoder the maximum number of bytes per
+ * line.
+ * </DL>
+ *
+ * Several useful encoders have already been written and are referenced in the
+ * See Also list below.
+ *
+ * @version 1.38, 11/17/05
+ * @author Chuck McManis
+ * @see CharacterDecoder;
+ * @see UCEncoder
+ * @see UUEncoder
+ * @see BASE64Encoder
+ */
+public abstract class CharacterEncoder {
+
+  /** Stream that understands "printing" */
+  protected PrintStream pStream;
+
+  /** Return the number of bytes per atom of encoding */
+  abstract protected int bytesPerAtom();
+
+  /** Return the number of bytes that can be encoded per line */
+  abstract protected int bytesPerLine();
+
+  /**
+   * Encode the prefix for the entire buffer. By default is simply opens the
+   * PrintStream for use by the other functions.
+   */
+  protected void encodeBufferPrefix(OutputStream aStream) throws IOException {
+    pStream = new PrintStream(aStream);
+  }
+
+  /**
+   * Encode the suffix for the entire buffer.
+   */
+  protected void encodeBufferSuffix(OutputStream aStream) throws IOException {
+  }
+
+  /**
+   * Encode the prefix that starts every output line.
+   */
+  protected void encodeLinePrefix(OutputStream aStream, int aLength)
+      throws IOException {
+  }
+
+  /**
+   * Encode the suffix that ends every output line. By default this method just
+   * prints a <newline> into the output stream.
+   */
+  protected void encodeLineSuffix(OutputStream aStream) throws IOException {
+    pStream.println();
+  }
+
+  /** Encode one "atom" of information into characters. */
+  abstract protected void encodeAtom(OutputStream aStream, byte someBytes[],
+      int anOffset, int aLength) throws IOException;
+
+  /**
+   * This method works around the bizarre semantics of BufferedInputStream's
+   * read method.
+   */
+  protected int readFully(InputStream in, byte buffer[])
+      throws java.io.IOException {
+    for (int i = 0; i < buffer.length; i++) {
+      int q = in.read();
+      if (q == -1)
+        return i;
+      buffer[i] = (byte) q;
+    }
+    return buffer.length;
+  }
+
+  /**
+   * Encode bytes from the input stream, and write them as text characters to
+   * the output stream. This method will run until it exhausts the input stream,
+   * but does not print the line suffix for a final line that is shorter than
+   * bytesPerLine().
+   */
+  public void encode(InputStream inStream, OutputStream outStream)
+      throws IOException {
+    int j;
+    int numBytes;
+    byte tmpbuffer[] = new byte[bytesPerLine()];
+
+    encodeBufferPrefix(outStream);
+
+    while (true) {
+      numBytes = readFully(inStream, tmpbuffer);
+      if (numBytes == 0) {
+        break;
+      }
+      encodeLinePrefix(outStream, numBytes);
+      for (j = 0; j < numBytes; j += bytesPerAtom()) {
+
+        if ((j + bytesPerAtom()) <= numBytes) {
+          encodeAtom(outStream, tmpbuffer, j, bytesPerAtom());
+        } else {
+          encodeAtom(outStream, tmpbuffer, j, (numBytes) - j);
+        }
+      }
+      if (numBytes < bytesPerLine()) {
+        break;
+      } else {
+        encodeLineSuffix(outStream);
+      }
+    }
+    encodeBufferSuffix(outStream);
+  }
+
+  /**
+   * Encode the buffer in <i>aBuffer</i> and write the encoded result to the
+   * OutputStream <i>aStream</i>.
+   */
+  public void encode(byte aBuffer[], OutputStream aStream) throws IOException {
+    ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
+    encode(inStream, aStream);
+  }
+
+  /**
+   * A 'streamless' version of encode that simply takes a buffer of bytes and
+   * returns a string containing the encoded buffer.
+   */
+  public String encode(byte aBuffer[]) {
+    ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+    ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
+    String retVal = null;
+    try {
+      encode(inStream, outStream);
+      // explicit ascii->unicode conversion
+      retVal = outStream.toString("8859_1");
+    } catch (Exception IOException) {
+      // This should never happen.
+      throw new Error("CharacterEncoder.encode internal error");
+    }
+    return (retVal);
+  }
+
+  /**
+   * Return a byte array from the remaining bytes in this ByteBuffer.
+   * <P>
+   * The ByteBuffer's position will be advanced to ByteBuffer's limit.
+   * <P>
+   * To avoid an extra copy, the implementation will attempt to return the byte
+   * array backing the ByteBuffer. If this is not possible, a new byte array
+   * will be created.
+   */
+  private byte[] getBytes(ByteBuffer bb) {
+    /*
+     * This should never return a BufferOverflowException, as we're careful to
+     * allocate just the right amount.
+     */
+    byte[] buf = null;
+
+    /*
+     * If it has a usable backing byte buffer, use it. Use only if the array
+     * exactly represents the current ByteBuffer.
+     */
+    if (bb.hasArray()) {
+      byte[] tmp = bb.array();
+      if ((tmp.length == bb.capacity()) && (tmp.length == bb.remaining())) {
+        buf = tmp;
+        bb.position(bb.limit());
+      }
+    }
+
+    if (buf == null) {
+      /*
+       * This class doesn't have a concept of encode(buf, len, off), so if we
+       * have a partial buffer, we must reallocate space.
+       */
+      buf = new byte[bb.remaining()];
+
+      /*
+       * position() automatically updated
+       */
+      bb.get(buf);
+    }
+
+    return buf;
+  }
+
+  /**
+   * Encode the <i>aBuffer</i> ByteBuffer and write the encoded result to the
+   * OutputStream <i>aStream</i>.
+   * <P>
+   * The ByteBuffer's position will be advanced to ByteBuffer's limit.
+   */
+  public void encode(ByteBuffer aBuffer, OutputStream aStream)
+      throws IOException {
+    byte[] buf = getBytes(aBuffer);
+    encode(buf, aStream);
+  }
+
+  /**
+   * A 'streamless' version of encode that simply takes a ByteBuffer and returns
+   * a string containing the encoded buffer.
+   * <P>
+   * The ByteBuffer's position will be advanced to ByteBuffer's limit.
+   */
+  public String encode(ByteBuffer aBuffer) {
+    byte[] buf = getBytes(aBuffer);
+    return encode(buf);
+  }
+
+  /**
+   * Encode bytes from the input stream, and write them as text characters to
+   * the output stream. This method will run until it exhausts the input stream.
+   * It differs from encode in that it will add the line at the end of a final
+   * line that is shorter than bytesPerLine().
+   */
+  public void encodeBuffer(InputStream inStream, OutputStream outStream)
+      throws IOException {
+    int j;
+    int numBytes;
+    byte tmpbuffer[] = new byte[bytesPerLine()];
+
+    encodeBufferPrefix(outStream);
+
+    while (true) {
+      numBytes = readFully(inStream, tmpbuffer);
+      if (numBytes == 0) {
+        break;
+      }
+      encodeLinePrefix(outStream, numBytes);
+      for (j = 0; j < numBytes; j += bytesPerAtom()) {
+        if ((j + bytesPerAtom()) <= numBytes) {
+          encodeAtom(outStream, tmpbuffer, j, bytesPerAtom());
+        } else {
+          encodeAtom(outStream, tmpbuffer, j, (numBytes) - j);
+        }
+      }
+      encodeLineSuffix(outStream);
+      if (numBytes < bytesPerLine()) {
+        break;
+      }
+    }
+    encodeBufferSuffix(outStream);
+  }
+
+  /**
+   * Encode the buffer in <i>aBuffer</i> and write the encoded result to the
+   * OutputStream <i>aStream</i>.
+   */
+  public void encodeBuffer(byte aBuffer[], OutputStream aStream)
+      throws IOException {
+    ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
+    encodeBuffer(inStream, aStream);
+  }
+
+  /**
+   * A 'streamless' version of encode that simply takes a buffer of bytes and
+   * returns a string containing the encoded buffer.
+   */
+  public String encodeBuffer(byte aBuffer[]) {
+    ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+    ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
+    try {
+      encodeBuffer(inStream, outStream);
+    } catch (Exception IOException) {
+      // This should never happen.
+      throw new Error("CharacterEncoder.encodeBuffer internal error");
+    }
+    return (outStream.toString());
+  }
+
+  /**
+   * Encode the <i>aBuffer</i> ByteBuffer and write the encoded result to the
+   * OutputStream <i>aStream</i>.
+   * <P>
+   * The ByteBuffer's position will be advanced to ByteBuffer's limit.
+   */
+  public void encodeBuffer(ByteBuffer aBuffer, OutputStream aStream)
+      throws IOException {
+    byte[] buf = getBytes(aBuffer);
+    encodeBuffer(buf, aStream);
+  }
+
+  /**
+   * A 'streamless' version of encode that simply takes a ByteBuffer and returns
+   * a string containing the encoded buffer.
+   * <P>
+   * The ByteBuffer's position will be advanced to ByteBuffer's limit.
+   */
+  public String encodeBuffer(ByteBuffer aBuffer) {
+    byte[] buf = getBytes(aBuffer);
+    return encodeBuffer(buf);
+  }
+
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/RemoteLoggingInitException.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/RemoteLoggingInitException.java
new file mode 100644
index 0000000..89f8a4e
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/RemoteLoggingInitException.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.lib.util;
+
+/**
+ * This exception is thrown by the init method of the TestUtil class, if
+ * anything goes wrong while establishing a socket connection back to the
+ * harness host.
+ * 
+ * @author Kyle Grucci
+ */
+public class RemoteLoggingInitException extends java.lang.Exception {
+  /**
+   * creates a RemoteLoggingInitException
+   */
+  public RemoteLoggingInitException() {
+    super();
+  }
+
+  /**
+   * creates a RemoteLoggingInitException with a message
+   * 
+   * @param s
+   *          the message
+   */
+  public RemoteLoggingInitException(String s) {
+    super(s);
+  }
+}
diff --git a/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/TestUtil.java b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/TestUtil.java
new file mode 100644
index 0000000..fe19465
--- /dev/null
+++ b/jaxrs-tck/src/main/java/jakarta/ws/rs/tck/lib/util/TestUtil.java
@@ -0,0 +1,1071 @@
+/*
+ * Copyright (c) 2007, 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * $Id$
+ */
+
+package jakarta.ws.rs.tck.lib.util;
+
+import java.io.*;
+import java.util.*;
+import java.net.*;
+import java.text.SimpleDateFormat;
+
+/**
+ * TestUtil is a final utility class responsible for implementing logging across
+ * multiple VMs. It also contains many convenience methods for logging property
+ * object contents, stacktraces, and header lines.
+ *
+ * @author Kyle Grucci
+ *
+ */
+public final class TestUtil {
+  public static boolean traceflag = Boolean.getBoolean("junit.log.traceflag");
+
+  // this can be set in TestUtil's start logging method!!
+  public static String sTestName;
+
+  public static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+  public static final int VM_UNDER_TEST = 0;
+
+  public static final int VM_HARNESS = 1; // this is really the test client VM
+
+  public static final int VM_JAVATEST = 2;
+
+  public static final int DEBUG_OUTPUT_LEVEL = 2;
+
+  public static final int NORMAL_OUTPUT_LEVEL = 3;
+
+  public static final int ERROR_STREAM = 4;
+
+  public static final int OUTPUT_STREAM = 5;
+
+  public static String NEW_LINE = System.getProperty("line.separator", "\n");
+
+  // by default so the testers don't have to do anything
+  public static int iWhereAreWe = VM_UNDER_TEST;
+
+  private static PrintWriter out = null;
+
+  private static PrintWriter err = null;
+
+  private static PrintWriter additionalWriter = null;
+
+  private static ObjectOutputStream objectOutputStream = null;
+
+  private static ObjectOutputStream objectInputStream = null;
+
+  private static Socket socketOnRemoteVM = null;
+
+  private static boolean bAlreadyInitialized = false;
+
+  private static Object socketMutex = new Object();
+
+  private static int portOfHarness = 2000;
+
+  private static String hostOfHarness = "unset host";
+
+  private static Vector vBuffereredOutput = new Vector();
+
+  // Transaction Attribute Value Mapping Table
+  private static final String UNRECOGNIZED_STATUS = "UNRECOGNIZED_STATUS";
+
+  private static final String transactionTable[] = { "STATUS_ACTIVE", // 0
+      "STATUS_MARKED_ROLLBACK", // 1
+      "STATUS_PREPARED", // 2
+      "STATUS_COMMITTED", // 3
+      "STATUS_ROLLEDBACK", // 4
+      "STATUS_UNKNOWN", // 5
+      "STATUS_NO_TRANSACTION", // 6
+      "STATUS_PREPARING", // 7
+      "STATUS_COMMITTING", // 8
+      "STATUS_ROLLING_BACK", // 9
+  };
+
+  // debug flag for printing TS harness debug output
+  public static boolean harnessDebug;
+
+  // hang onto the props that are passed in during logging init calls
+  private static Properties testProps = null;
+
+  private static SimpleDateFormat df = new SimpleDateFormat(
+      "MM-dd-yyyy HH:mm:ss");
+
+  static {
+    harnessDebug = Boolean.getBoolean("cts.harness.debug");
+  }
+
+  /**
+   * used by harness to log debug output to the standard output stream
+   * 
+   * @param s
+   *          the output string
+   */
+  public static void logHarnessDebug(String s) {
+    if (harnessDebug) {
+      logHarness(s, null);
+    }
+  }
+
+  /**
+   * used by TSTestFinder and TSScript to log output to the standard output
+   * stream
+   *
+   * @param s
+   *          the output string
+   * @param t
+   *          a Throwable whose stacktrace gets printed
+   */
+  public static void logHarness(String s, Throwable t) {
+    synchronized (System.out) {
+      System.out.println(df.format(new Date()) + ":" + s);
+      //logToAdditionalWriter(s, t);
+      if (t != null) {
+        t.printStackTrace();
+      }
+    }
+  }
+
+  public static void logHarness(String s) {
+    logHarness(s, null);
+  }
+
+  private static void logToAdditionalWriter(String s) {
+    logToAdditionalWriter(s, null);
+  }
+
+  private static void logToAdditionalWriter(String s, Throwable t) {
+    if (additionalWriter != null)
+      additionalWriter.println(s);
+    if (t != null) {
+      t.printStackTrace(additionalWriter);
+    }
+  }
+
+  /**
+   * This method returns the properties object
+   *
+   * @return the properties object
+   */
+  public static Properties getProperties() {
+    if (testProps == null) {
+      testProps = getPropsFromFile();
+    }
+    return testProps;
+  }
+
+  /**
+   * This method returns the property value for the appropriate property key
+   *
+   * @param s
+   *          the property name
+   * @return the property value
+   */
+  public static String getProperty(String s) {
+    Properties p = getProperties();
+    return p.getProperty(s);
+  }
+
+  /**
+   * This method returns the property value for the appropriate property key
+   * 
+   * @param s
+   *          the property name
+   * @return the property value
+   */
+  public static String getProperty(String s, String defaultValue) {
+    Properties p = getProperties();
+    return p.getProperty(s, defaultValue);
+  }
+
+  /**
+   * returns the transaction status value as a String given its integer
+   * representation
+   *
+   * @param status
+   *          integer representation of a transaction status
+   * @return string representation of a transaction status
+   */
+  public static String getTransactionStatus(int status) {
+    if (status < 0 || status > transactionTable.length - 1)
+      return UNRECOGNIZED_STATUS;
+    else
+      return transactionTable[status];
+  }
+
+  /**
+   * prints the transaction status value as a String given its integer
+   * representation
+   *
+   * @param status
+   *          integer representation of a transaction status
+   */
+  public static void printTransactionStatus(int status) {
+    logMsg("TRANSACTION_STATUS: " + getTransactionStatus(status));
+  }
+
+  // MilliSeconds Multiple
+  public static final int MILLI = 1000;
+
+  /**
+   * pauses the calling thread for the specified number of seconds
+   *
+   * @param s
+   *          number of seconds
+   */
+  public static void sleepSec(int s) {
+    logTrace("Sleeping " + s + " seconds");
+    try {
+      Thread.sleep(s * MILLI);
+    } catch (InterruptedException e) {
+      logErr("Exception: " + e);
+    }
+  }
+
+  /**
+   * pauses the calling thread for the specified number of milliseconds
+   *
+   * @param s
+   *          number of milliseconds
+   */
+  public static void sleep(int s) {
+    sleepMsec(s);
+  }
+
+  /**
+   * pauses the calling thread for the specified number of milliseconds
+   *
+   * @param s
+   *          number of milliseconds
+   */
+  public static void sleepMsec(int s) {
+    logTrace("Sleeping " + s + " milliseconds");
+    try {
+      Thread.sleep(s);
+    } catch (InterruptedException e) {
+      logErr("Exception: " + e);
+    }
+  }
+
+  public static void flushStream() {
+    synchronized (socketMutex) {
+      try {
+        objectOutputStream.flush();
+      } catch (Throwable t) {
+        // Ignore
+        // System.out.println("EXCEPTION WHILE FLUSHING");
+      }
+    }
+  }
+
+  public static void writeObject(TestReportInfo info) {
+    synchronized (socketMutex) {
+      flushStream();
+      try {
+        objectOutputStream.writeObject(info);
+        // System.out.println("WROTE: " + info.sOutput);
+      } catch (Exception e) {
+        // System.out.println("EXCEPTION WHILE WRITING: " + info.sOutput);
+        synchronized (vBuffereredOutput) {
+          vBuffereredOutput.addElement(info);
+          // System.out.println("ADDED THIS STRING TO BUFFERED OUT: " +
+          // info.sOutput);
+        }
+      }
+      flushStream();
+    }
+  }
+
+  private static void sendBufferedData() throws Exception {
+    TestReportInfo tri = null;
+    synchronized (vBuffereredOutput) {
+      try {
+        // logMsg("vBuffereredOutput size = " + vBuffereredOutput.size());
+        synchronized (socketMutex) {
+          for (int ii = 0; ii < vBuffereredOutput.size(); ii++) {
+            tri = (TestReportInfo) vBuffereredOutput.elementAt(ii);
+            writeObject(tri);
+            // System.out.println("WRITING_bufferedoutput: " + tri.sOutput);
+            // objectOutputStream.writeObject(tri);
+            // objectOutputStream.flush();
+            // logMsg("writing: " + ii);
+            // logMsg("writing: " + tri.sOutput);
+          }
+        }
+        // logMsg("wrote buffered output");
+      } catch (Exception e) {
+        throw e;
+      } finally {
+        vBuffereredOutput.removeAllElements();
+        // logMsg("reinititialized buffered output vector");
+      }
+    }
+  }
+
+  private static final String PROPS_FILE_NAME = "-cts-props.txt";
+
+  private static final String PROPS_FILE;
+
+  static {
+    String userName = System.getProperty("user.name");
+    String tmpDir = System.getProperty("java.io.tmpdir",
+        File.separator + "tmp");
+    if (tmpDir.endsWith(File.separator)) {
+      PROPS_FILE = tmpDir + userName + PROPS_FILE_NAME;
+    } else {
+      PROPS_FILE = tmpDir + File.separator + userName + PROPS_FILE_NAME;
+    }
+    System.out.println(
+        "************************************************************");
+    System.out.println("* props file set to \"" + PROPS_FILE + "\"");
+    System.out.println(
+        "************************************************************");
+  }
+
+  private static Properties getPropsFromFile() {
+    FileInputStream in = null;
+    Properties p = new Properties();
+    try {
+      in = new FileInputStream(PROPS_FILE);
+      p.load(in);
+    } catch (Exception e) {
+      logErr("Error reading the Properties object", e);
+    } finally {
+      if (in != null) {
+        try {
+          in.close();
+        } catch (Exception e) {
+        }
+      }
+    }
+    return p;
+  }
+
+  private static void savePropsToFile(Properties p) {
+    FileOutputStream out = null;
+    try {
+      out = new FileOutputStream(PROPS_FILE);
+      p.store(out, "CTS Test Properties File");
+    } catch (Exception e) {
+      logErr("Error saving the Properties object", e);
+    } finally {
+      if (out != null) {
+        try {
+          out.close();
+        } catch (Exception e) {
+        }
+      }
+    }
+  }
+
+  /**
+   * This static method must be called once by each new remote VM. Once called,
+   * a socket connection is created back to the host running the test harness.
+   * All calls to logMsg, logErr, and logTrace are immediately sent back to the
+   * harness host.
+   *
+   * @param p
+   *          properties containing harness host, port, and trace flag
+   * @exception RemoteLoggingInitException
+   *              if an exception occurs while the server side is setting up the
+   *              socket connection back to the client host
+   */
+  public static void init(Properties p) throws RemoteLoggingInitException {
+    savePropsToFile(p); // persist properties to a disk file
+    // System.out.println("INIT_CALLED");
+    synchronized (socketMutex) {
+      try {
+        // TSPropertyManager.createTSPropertyManager(p);
+        testProps = p;
+        if (p.isEmpty()) {
+          throw new RemoteLoggingInitException(
+              "Init: Error - Empty properties object passed to TestUtil.init");
+        }
+        NEW_LINE = p.getProperty("line.separator");
+        if (socketOnRemoteVM != null) {
+          socketOnRemoteVM.close();
+        }
+        if (objectOutputStream != null) {
+          objectOutputStream.close();
+        }
+        if (true) {
+          // System.out.println("INIT_CALLED AND SOCKET = NULL");
+          traceflag = Boolean
+              .valueOf(p.getProperty("harness.log.traceflag", "true"))
+              .booleanValue();
+          hostOfHarness = p.getProperty("harness.host");
+          portOfHarness = Integer
+              .parseInt(p.getProperty("harness.log.port", "2000"));
+          if (hostOfHarness == null) {
+            throw new RemoteLoggingInitException(
+                "Init: Error while trying to getProperty(harness.host) - returned null");
+          }
+          socketOnRemoteVM = new Socket(hostOfHarness, portOfHarness);
+          objectOutputStream = new ObjectOutputStream(
+              socketOnRemoteVM.getOutputStream());
+          sendBufferedData();
+          // logMsg("socketOnRemoteVM=null, renewed everything");
+        } else {
+          // we'll never get here now...
+          // call flush to make sure that we still have an open connection.
+          // if the client went away and a new client is being run, we will
+          // get an IOException, in which case we will reconnect.
+          // logMsg("socketOnRemoteVM != null, calling flush");
+          // objectOutputStream.flush();
+          // if this fails, then the connection is gone
+          // this is better than flush, because flush seems to always fail
+          TestReportInfo tri = new TestReportInfo("SVR: " + "Logging check",
+              OUTPUT_STREAM, DEBUG_OUTPUT_LEVEL, null);
+          objectOutputStream.writeObject(tri);
+          // System.out.println("WROTE TEST OBJECT");
+        }
+      } catch (UnknownHostException e) {
+        throw new RemoteLoggingInitException(
+            "You must pass a valid host string to init()");
+      } catch (IOException e) {
+        // System.out.println("EXCEPTION WHILE WRITING TEST OBJECT");
+        // the client VM may have shutdown, so establish a new connection
+        try {
+          // System.out.println("INIT_CALLED AND TRYING TO ESABLISH CONN. AFTER
+          // IOEXCEPTION");
+          traceflag = Boolean
+              .valueOf(p.getProperty("harness.log.traceflag", "true"))
+              .booleanValue();
+          hostOfHarness = p.getProperty("harness.host");
+          portOfHarness = Integer
+              .parseInt(p.getProperty("harness.log.port", "2000"));
+          if (hostOfHarness == null) {
+            throw new RemoteLoggingInitException(
+                "Init: Error while trying to getProperty(harness.host) - returned null");
+          }
+          socketOnRemoteVM.close();
+          socketOnRemoteVM = new Socket(hostOfHarness, portOfHarness);
+          objectOutputStream = new ObjectOutputStream(
+              socketOnRemoteVM.getOutputStream());
+          sendBufferedData();
+          // logMsg("caught IOException from flush(), renewed everything");
+        } catch (IOException e2) {
+          e2.printStackTrace();
+          throw new RemoteLoggingInitException(
+              "IOException in TestUtil.init()");
+        } catch (Exception e2) {
+          e2.printStackTrace();
+          throw new RemoteLoggingInitException(
+              "got a random exception in init()");
+        }
+      } catch (NumberFormatException e) {
+        throw new RemoteLoggingInitException(
+            "You must pass a valid port number string to init()");
+      } catch (Exception e) {
+        e.printStackTrace();
+        throw new RemoteLoggingInitException(
+            "got a random exception in init()");
+      }
+    }
+  }
+
+  /*
+   * This method is called by our harness code to allow code that is shared
+   * between the harness and the tests and calls TestUtil logMsg and logTrace to
+   * do the right thing inside of the JavaTest VM. These calls will call to our
+   * logHarness methods.
+   */
+  public static void initJavaTest() {
+    iWhereAreWe = VM_JAVATEST;
+  }
+
+  public static void setAdditionalWriter(PrintWriter pw) {
+    iWhereAreWe = VM_JAVATEST;
+    additionalWriter = pw;
+  }
+
+  /**
+   * This static method must be called once by a VM which does not rely upon any
+   * remote logging.
+   *
+   * param p properties containing harness trace flag
+   */
+  public static void initNoLogging(Properties p) {
+    if (bAlreadyInitialized)
+      return;
+
+    testProps = p;
+    NEW_LINE = p.getProperty("line.separator");
+    traceflag = Boolean.valueOf(p.getProperty("harness.log.traceflag", "true"))
+        .booleanValue();
+    iWhereAreWe = VM_HARNESS;
+    bAlreadyInitialized = true;
+  }
+
+  /**
+   * This static method must be called once by the harness VM. Once called, a
+   * serversocket begins listening for Remote VMs to connect on the port
+   * specified by harness.log.port.
+   *
+   * @param p
+   *          properties containing harness trace flag
+   */
+  public static void initClient(Properties p) {
+    if (bAlreadyInitialized)
+      return;
+    // start listener thread
+    try {
+      testProps = p;
+      NEW_LINE = p.getProperty("line.separator");
+      traceflag = Boolean
+          .valueOf(p.getProperty("harness.log.traceflag", "true"))
+          .booleanValue();
+      iWhereAreWe = VM_HARNESS;
+      ServerSocket ss = getServerSocket(p);
+      new Acceptor(ss);
+      bAlreadyInitialized = true;
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+  }
+
+  private static ServerSocket getServerSocket(Properties p) throws IOException {
+    ServerSocket result = null;
+    int port = 2000;
+    int retry = 10;
+    final int delaySeconds = 1;
+    try {
+      port = Integer.parseInt(p.getProperty("harness.log.port", "2000"));
+    } catch (NumberFormatException e1) {
+      e1.printStackTrace();
+      System.err.println("Invalid value for harness.log.port,"
+          + " using default harness.log.port of " + port);
+    }
+    try {
+      retry = Integer
+          .parseInt(p.getProperty("harness.socket.retry.count", "10"));
+    } catch (NumberFormatException e2) {
+      e2.printStackTrace();
+      System.err.println("Invalid value for harness.socket.retry.count,"
+          + " using default harness.socket.retry.count of " + retry);
+    }
+    logTrace(
+        "#######  Value of harness.socket.retry.count is \"" + retry + "\"");
+    logTrace("#######  Value of harness.log.port is \"" + port + "\"");
+    result = getServerSocket0(port, retry, delaySeconds);
+    while (result == null) {
+      port++;
+      result = getServerSocket0(port, retry, delaySeconds);
+    }
+    p.setProperty("harness.log.port", Integer.toString(port));
+    logTrace(
+        "#######  Actual bind value of harness.log.port is \"" + port + "\"");
+    return result;
+  }
+
+  private static ServerSocket getServerSocket0(int port, int retry,
+      int delaySeconds) {
+    ServerSocket result = null;
+    for (int i = 0; i < retry; i++) {
+      try {
+        result = new ServerSocket(port);
+        break;
+      } catch (IOException e3) {
+        try {
+          Thread.sleep(delaySeconds * 1000);
+        } catch (InterruptedException e4) {
+        }
+      }
+    }
+    return result;
+  }
+
+  /**
+   * This static method must be called once by the harness VM in order to set
+   * the output and error streams and the name of the current test.
+   *
+   * @param testName
+   *          the currently running testname as specified in the source code
+   *          tags
+   * @param outStream
+   *          stream printed to by the logMsg and logTrace methods
+   * @param errStream
+   *          stream printed to by the logErr methods
+   */
+  public static void setCurrentTest(String testName, PrintWriter outStream,
+      PrintWriter errStream) {
+    sTestName = testName;
+    out = outStream;
+    err = outStream;
+  }
+
+  /**
+   * prints a string to the log stream. All tests should use this method for
+   * standard logging messages
+   *
+   * @param s
+   *          string to print to the log stream
+   */
+  public static void logMsg(String s) {
+    logHarness(s);
+  }
+
+  /**
+   * prints a string as well as the provided Throwable's stacktrace to the log
+   * stream. All tests should use this method for standard logging messages
+   *
+   * @param s
+   *          string to print to the log stream
+   * @param t
+   *          - throwable whose stacktrace gets printed*
+   *
+   */
+  public static void logMsg(String s, Throwable t) {
+    logHarnessDebug(s);
+    if (t != null) {
+      t.printStackTrace();
+    }
+  }
+
+  /**
+   * turns on/off debugging. Once on, all calls to the logTrace method result in
+   * messages being printed to the log stream. If off, all logTrace calls are
+   * not printed.
+   *
+   * @param b
+   *          If <code>true</code>, debugging is on. If false, debugging is
+   *          turned off.
+   */
+  public static void setTrace(boolean b) {
+    traceflag = b;
+  }
+
+  /**
+   * prints a debug string to the log stream. All tests should use this method
+   * for verbose logging messages. Whether or not the string is printed is
+   * determined by the last call to the setTrace method.
+   *
+   * @param s
+   *          string to print to the log stream
+   */
+  public static void logTrace(String s) {
+    logTrace(s, null);
+  }
+
+  /**
+   * Prints a debug string as well as the provided Throwable's stacktrace. Use
+   * this if certain exceptions are only desired while tracing.
+   *
+   * @param s
+   *          - string to print to the log stream
+   * @param t
+   *          - throwable whose stactrace gets printed
+   */
+  public static void logTrace(String s, Throwable t) {
+    if (traceflag) {
+      logHarnessDebug(s);
+      if (t != null) {
+        t.printStackTrace();
+      }
+    }
+  }
+
+  /**
+   * prints an error string to the error stream. All tests should use this
+   * method for error messages.
+   *
+   * @param s
+   *          string to print to the error stream
+   * @param e
+   *          a Throwable whose stacktrace gets printed
+   */
+  public static void logErr(String s, Throwable e) {
+    logHarness(s);
+    if (e != null) {
+      e.printStackTrace();
+    }
+  }
+
+  /**
+   * prints an error string to the error stream. All tests should use this
+   * method for error messages.
+   *
+   * @param s
+   *          string to print to the error stream
+   */
+  public static void logErr(String s) {
+    logErr(s, null);
+  }
+
+  /**
+   * prints the contents of a properties object to the logging stream
+   *
+   * @param p
+   *          properties to print
+   */
+  public static void list(Properties p) {
+    StringBuffer sb = new StringBuffer();
+    if (p == null)
+      return;
+    sb.append("--- Property Listing ---").append(TestUtil.NEW_LINE);
+    Enumeration e = p.propertyNames();
+    String key = null;
+    while (e.hasMoreElements()) {
+      key = (String) e.nextElement();
+      sb.append(key).append("=").append(p.getProperty(key))
+          .append(TestUtil.NEW_LINE);
+    }
+    sb.append("--- End Property Listing ---").append(TestUtil.NEW_LINE);
+    logTrace(new String(sb));
+  }
+
+  /**
+   * prints the stacktrace of a Throwable to the logging stream
+   *
+   * @param e
+   *          exception to print the stacktrace of
+   */
+  public static void printStackTrace(Throwable e) {
+    if (e == null) {
+      return;
+    }
+    try {
+      StringWriter sw = new StringWriter();
+      PrintWriter writer = new PrintWriter(sw);
+      e.printStackTrace(writer);
+      logErr(sw.toString());
+      writer.close();
+    } catch (Exception E) {
+    }
+  }
+
+  /**
+   * prints the stacktrace of a Throwable to a string
+   *
+   * @param e
+   *          exception to print the stacktrace of
+   */
+  public static String printStackTraceToString(Throwable e) {
+    String sTrace = "";
+    if (e == null)
+      return "";
+    try {
+      StringWriter sw = new StringWriter();
+      PrintWriter writer = new PrintWriter(sw);
+      e.printStackTrace(writer);
+      sTrace = sw.toString();
+      writer.close();
+    } catch (Exception E) {
+    }
+    return sTrace;
+  }
+
+  /**
+   * prints a line of asterisks to the logging stream
+   */
+  public static void separator2() {
+    logMsg("**************************************************"
+        + "******************************");
+  }
+
+  /**
+   * prints a line of dashes to the logging stream
+   */
+  public static void separator1() {
+    logMsg("--------------------------------------------------"
+        + "------------------------------");
+  }
+
+  /**
+   * Convience method to handle sucking in the data from a connection.
+   */
+  public static String getResponse(URLConnection connection)
+      throws IOException {
+    StringBuffer content;
+    BufferedReader in;
+    // set up the streams / readers
+    InputStream instream = connection.getInputStream();
+    InputStreamReader inreader = new InputStreamReader(instream);
+    in = new BufferedReader(inreader);
+    // data structures
+    content = new StringBuffer(1024);
+    char[] chars = new char[1024];
+    int length = 0;
+    // pull the data into the content buffer
+    while (length != -1) {
+      content.append(chars, 0, length);
+      length = in.read(chars, 0, chars.length);
+    }
+    // return
+    instream.close(); // john feb 16
+    inreader.close(); // john feb 16
+    in.close(); // john feb 16
+    return content.toString();
+  }
+
+  /**
+   * Loads any properties that might be in a given String.
+   */
+  public static Properties getResponseProperties(String string)
+      throws IOException {
+    Properties props;
+    ByteArrayInputStream in;
+    byte[] bytes;
+    props = new Properties();
+    bytes = string.getBytes();
+    in = new ByteArrayInputStream(bytes);
+    props.load(in);
+    in.close();
+    return props;
+  }
+
+  /**
+   * One shot method to get Properties directly from a URLConnection.
+   */
+  public static Properties getResponseProperties(URLConnection connection)
+      throws IOException {
+    Properties props;
+    String input;
+    input = getResponse(connection);
+    props = getResponseProperties(input);
+    return props;
+  }
+
+  public static String toEncodedString(Properties args) {
+    StringBuffer buf = new StringBuffer();
+    Enumeration names = args.propertyNames();
+    while (names.hasMoreElements()) {
+      String name = (String) names.nextElement();
+      String value = args.getProperty(name);
+      buf.append(URLEncoder.encode(name)).append("=")
+          .append(URLEncoder.encode(value));
+      if (names.hasMoreElements())
+        buf.append("&");
+    }
+    return buf.toString();
+  }
+
+  public static URLConnection sendPostData(Properties p, URL url)
+      throws IOException {
+    TestUtil.logMsg("Openning url connection to: " + url.toString());
+    URLConnection urlConn = url.openConnection();
+    // Begin POST of properties to SERVLET
+    String argString = TestUtil.toEncodedString(p);
+    urlConn.setDoOutput(true);
+    urlConn.setDoInput(true);
+    urlConn.setUseCaches(false);
+    DataOutputStream out = new DataOutputStream(urlConn.getOutputStream());
+    out.writeBytes(argString);
+    out.flush();
+    out.close();
+    // End POST
+    return urlConn;
+  }
+
+  /**
+   * Parse a the table name from the ddl string such as: "create table foo" or
+   * "delete from foo"
+   * 
+   * @param value
+   *          buffer to parse
+   * @return The name of the table
+   */
+  public static String getTableName(String value) {
+    String tableName = "";
+    if (value != null) {
+      tableName = value.trim();
+      int pos = tableName.lastIndexOf(" ");
+      tableName = tableName.substring(pos + 1);
+    } else {
+      TestUtil.logMsg("Error: Null value passed for table Name");
+    }
+    return (tableName);
+  } // END -- getTableName
+
+  public static String srcToDist(String src) {
+    return replaceLastSrc(src, "dist");
+  }
+
+  public static String replaceLastSrc(String src, String replacement) {
+    // find last index of /src/, remove "src", then replace it with replacement
+    StringBuffer sbToConvert = new StringBuffer(src);
+    int iStart = src.lastIndexOf("src");
+    if (iStart != -1) {
+      if (harnessDebug) {
+        TestUtil.logHarnessDebug("Pre-converted src dir = " + sbToConvert);
+      }
+      sbToConvert.replace(iStart, iStart + 3, replacement);
+
+      if (harnessDebug) {
+        TestUtil.logHarnessDebug(
+            "Converted " + replacement + " dir = " + sbToConvert);
+      }
+    }
+    return sbToConvert.toString();
+  }
+
+  public static String getDistString() {
+    // we may need to default to src until we are ready to convert for good
+    return "dist";
+  }
+
+  public static String getRelativePath(String oldVal) {
+    if (oldVal == null) {
+      return oldVal;
+    }
+    String result = oldVal;
+    oldVal = oldVal.replace('\\', '/');
+    while (oldVal.endsWith("/")) {
+      oldVal = oldVal.substring(0, oldVal.length() - 1);
+    }
+    if (oldVal.endsWith("/src")) {
+      return result;
+    }
+    int pos = oldVal.indexOf("/src/");
+    if (pos == -1) {
+      pos = oldVal.indexOf("/dist/");
+      if (pos == -1) {
+        result = oldVal;
+      } else {
+        result = oldVal.substring(pos + 6); // len of '/dist/'
+      }
+    } else {
+      result = oldVal.substring(pos + 5);
+    }
+    return result;
+  }
+
+  // Convert the given string of key-value-pair into a properties object
+  //
+  // for example :
+  // DatabaseName=derbyDB:user=cts1:password=cts1:serverName=localhost:portNumber=1527
+  //
+  public static Properties strToProps(String strProps) {
+
+    logTrace("Props String = " + strProps);
+    Properties props = new Properties();
+    String strArray[] = strProps.split(":"); // Split the given string into
+                                             // array of key value pairs
+
+    for (String keyValuePair : strArray) {
+      String strArray2[] = keyValuePair.split("="); // Take the key value pair
+                                                    // and store it into
+                                                    // properties
+      logTrace("Setting property " + strArray2[0] + " = " + strArray2[1]);
+      props.setProperty(strArray2[0], strArray2[1]);
+    }
+
+    return props;
+
+  }
+
+  public static void printProperties(Properties props) {
+    Set<String> propertyNames = props.stringPropertyNames();
+    for (String key : propertyNames) {
+      logTrace(key + " = " + props.getProperty(key));
+    }
+  }
+
+}
+
+// ======================= end of class TestUtil ======================
+
+class Acceptor extends Thread {
+  ServerSocket serverSocket;
+
+  private Socket outputSocket = null;
+
+  public Acceptor(ServerSocket ss) {
+    serverSocket = ss;
+    this.start();
+  }
+
+  public void run() {
+    while (true) {
+      try {
+        outputSocket = serverSocket.accept();
+        new SocketReader(outputSocket);
+        // System.out.println("new connection!!!!!");
+      } catch (IOException ex) {
+        ex.printStackTrace();
+      }
+    }
+  }
+}
+
+class TestReportInfo implements Serializable {
+  public int iDebugLevel = TestUtil.NORMAL_OUTPUT_LEVEL;
+
+  public String sOutput = ""; // Constants.EMPTY_STRING;
+
+  public Throwable exception = null;
+
+  public int iStream = TestUtil.OUTPUT_STREAM;
+
+  public TestReportInfo(String output, int stream, int level, Throwable e) {
+    if (sOutput != null)
+      sOutput = output;
+    iDebugLevel = level;
+    exception = e;
+    iStream = stream;
+  }
+}
+
+class SocketReader extends Thread {
+  private Socket outputSocket = null;
+
+  public SocketReader(Socket s) {
+    outputSocket = s;
+    this.start();
+  }
+
+  public void run() {
+    ObjectInputStream objIn;
+    TestReportInfo tri = null;
+    try {
+      objIn = new ObjectInputStream(outputSocket.getInputStream());
+      // while((tri = (TestReportInfo)objIn.readObject()) != null)
+      while (true) {
+        tri = (TestReportInfo) objIn.readObject();
+        if (tri.iDebugLevel == TestUtil.DEBUG_OUTPUT_LEVEL) {
+          // System.out.println("about to call logTrace");
+          TestUtil.logTrace(tri.sOutput);
+        } else {
+          if (tri.iStream == TestUtil.ERROR_STREAM) {
+            if (tri.exception == null)
+              TestUtil.logErr(tri.sOutput);
+            else
+              TestUtil.logErr(tri.sOutput, tri.exception);
+            // System.out.println("about to call logErr");
+          } else // assume outputstream
+          {
+            // System.out.println("about to call logMsg");
+            TestUtil.logMsg(tri.sOutput);
+          }
+        }
+      }
+    } catch (EOFException e) {
+      // do nothing since the eof broke us out of the loop
+    } catch (ClassNotFoundException e) {
+      e.printStackTrace();
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+    // cleanup socket no matter what happens
+    /*
+     * try { outputSocket.close(); outputSocket = null; } catch(IOException e) {
+     * 
+     * }
+     */
+  }
+}
diff --git a/jaxrs-tck/src/main/resources/jakarta/ws/rs/tck/ee/rs/client/asyncinvoker/web.xml.template b/jaxrs-tck/src/main/resources/jakarta/ws/rs/tck/ee/rs/client/asyncinvoker/web.xml.template
new file mode 100644
index 0000000..5f08e7e
--- /dev/null
+++ b/jaxrs-tck/src/main/resources/jakarta/ws/rs/tck/ee/rs/client/asyncinvoker/web.xml.template
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Public License v. 2.0, which is available at
+    http://www.eclipse.org/legal/epl-2.0.
+
+    This Source Code may also be made available under the following Secondary
+    Licenses when the conditions for such availability set forth in the
+    Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+    version 2 with the GNU Classpath Exception, which is available at
+    https://www.gnu.org/software/classpath/license.html.
+
+    SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+
+<web-app version="5.0" xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd">
+    <servlet>
+        <servlet-name>CTS_JAXRS_SPEC_CLIENT_ASYNC_INVOKER</servlet-name>
+        <servlet-class>servlet_adaptor</servlet-class>
+        <init-param>
+            <param-name>jakarta.ws.rs.Application</param-name>
+            <param-value>jakarta.ws.rs.tck.ee.rs.client.asyncinvoker.TSAppConfig</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>CTS_JAXRS_SPEC_CLIENT_ASYNC_INVOKER</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+    <session-config>
+        <session-timeout>30</session-timeout>
+    </session-config>
+</web-app>
diff --git a/jaxrs-tck/src/main/resources/jakarta/ws/rs/tck/ee/rs/core/request/web.xml.template b/jaxrs-tck/src/main/resources/jakarta/ws/rs/tck/ee/rs/core/request/web.xml.template
new file mode 100644
index 0000000..1a7f175
--- /dev/null
+++ b/jaxrs-tck/src/main/resources/jakarta/ws/rs/tck/ee/rs/core/request/web.xml.template
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2007, 2020 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Public License v. 2.0, which is available at
+    http://www.eclipse.org/legal/epl-2.0.
+
+    This Source Code may also be made available under the following Secondary
+    Licenses when the conditions for such availability set forth in the
+    Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+    version 2 with the GNU Classpath Exception, which is available at
+    https://www.gnu.org/software/classpath/license.html.
+
+    SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+
+<web-app version="5.0" xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd">
+    <servlet>
+        <servlet-name>CTSJAX-RSCOREREQUEST</servlet-name>
+        <servlet-class>servlet_adaptor</servlet-class>
+        <init-param>
+            <param-name>jakarta.ws.rs.Application</param-name>
+            <param-value>jakarta.ws.rs.tck.ee.rs.core.request.TSAppConfig</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>CTSJAX-RSCOREREQUEST</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+    <session-config>
+        <session-timeout>30</session-timeout>
+    </session-config>
+</web-app>
diff --git a/jersey-tck/pom.xml b/jersey-tck/pom.xml
index 1699011..b53bcad 100644
--- a/jersey-tck/pom.xml
+++ b/jersey-tck/pom.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
     <groupId>org.glassfish.jersey.core</groupId>
@@ -11,16 +12,28 @@
     <description>This test verifies the compliance of Eclipse Jersey with Jakarta REST</description>
 
     <properties>
-        <maven.compiler.source>1.8</maven.compiler.source>
-        <maven.compiler.target>1.8</maven.compiler.target>
+        <maven.compiler.source>11</maven.compiler.source>
+        <maven.compiler.target>11</maven.compiler.target>
+        <jersey.version>3.0.0</jersey.version>
+        <glassfish.container.version>6.1.0</glassfish.container.version>
+        <jakarta.platform.version>9.1.0</jakarta.platform.version>
+        <junit.jupiter.version>5.7.2</junit.jupiter.version>
+        <jakarta.rest.version>3.0.0</jakarta.rest.version>
     </properties>
 
     <dependencyManagement>
         <dependencies>
             <dependency>
+                <groupId>org.junit</groupId>
+                <artifactId>junit-bom</artifactId>
+                <version>${junit.jupiter.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
                 <groupId>org.glassfish.jersey</groupId>
                 <artifactId>jersey-bom</artifactId>
-                <version>3.0.0</version>
+                <version>${jersey.version}</version>
                 <type>pom</type>
                 <scope>import</scope>
             </dependency>
@@ -29,6 +42,18 @@
 
     <dependencies>
         <dependency>
+            <groupId>org.glassfish.hk2</groupId>
+            <artifactId>hk2-locator</artifactId>
+            <version>3.0.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.jboss.arquillian.container</groupId>
+            <artifactId>arquillian-glassfish-managed-6</artifactId>
+            <version>1.0.0.Alpha1</version>
+        </dependency>
+
+        <dependency>
             <groupId>jakarta.ws.rs</groupId>
             <artifactId>jakarta.ws.rs-tck</artifactId>
             <version>3.1-SNAPSHOT</version>
@@ -36,24 +61,38 @@
         </dependency>
 
         <dependency>
-            <groupId>org.glassfish.jersey.inject</groupId>
-            <artifactId>jersey-hk2</artifactId>
-            <scope>test</scope>
+            <groupId>org.glassfish.main.common</groupId>
+            <artifactId>simple-glassfish-api</artifactId>
+            <version>${glassfish.container.version}</version>
         </dependency>
 
         <dependency>
-            <groupId>org.glassfish.jersey.core</groupId>
-            <artifactId>jersey-server</artifactId>
-            <scope>test</scope>
+            <groupId>org.jboss.arquillian.junit5</groupId>
+            <artifactId>arquillian-junit5-container</artifactId>
+            <version>1.7.0.Alpha10</version>
         </dependency>
 
         <dependency>
-            <groupId>org.glassfish.jersey.containers</groupId>
-            <artifactId>jersey-container-grizzly2-http</artifactId>
-            <scope>test</scope>
+            <groupId>jakarta.platform</groupId>
+            <artifactId>jakarta.jakartaee-api</artifactId>
+            <version>${jakarta.platform.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-httpclient</groupId>
+            <artifactId>commons-httpclient</artifactId>
+            <version>3.1</version>
         </dependency>
     </dependencies>
 
+
+    <profiles>
+        <profile>
+            <id>arq-glassfish-managed</id>
+        </profile>
+    </profiles>
+
     <build>
         <plugins>
             <plugin>
@@ -67,6 +106,136 @@
                         </goals>
                         <configuration>
                             <dependenciesToScan>jakarta.ws.rs:jakarta.ws.rs-tck</dependenciesToScan>
+                            <systemPropertyVariables>
+                                <GLASSFISH_HOME>${project.build.directory}/glassfish6</GLASSFISH_HOME>
+                                <servlet_adaptor>org.glassfish.jersey.servlet.ServletContainer</servlet_adaptor>
+                                <webServerHost>localhost</webServerHost>
+                                <webServerPort>8080</webServerPort>
+                                <junit.log.traceflag>true</junit.log.traceflag>
+                                <porting.ts.url.class.1>jakarta.ws.rs.tck.lib.implementation.sun.common.SunRIURL</porting.ts.url.class.1>
+                            </systemPropertyVariables>
+                            <environmentVariables>
+                                <GLASSFISH_HOME>${project.build.directory}/glassfish6</GLASSFISH_HOME>
+                            </environmentVariables>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <version>3.2.0</version>
+                <executions>
+                    <execution>
+                        <id>unpack</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.glassfish.main.distributions</groupId>
+                                    <artifactId>glassfish</artifactId>
+                                    <version>${glassfish.container.version}</version>
+                                    <type>zip</type>
+                                    <overWrite>false</overWrite>
+                                    <outputDirectory>${project.build.directory}</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>copy</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.glassfish.jersey.core</groupId>
+                                    <artifactId>jersey-client</artifactId>
+                                    <version>${jersey.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>${project.build.directory}/glassfish6/glassfish/modules</outputDirectory>
+                                    <destFileName>jersey-client.jar</destFileName>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.glassfish.jersey.core</groupId>
+                                    <artifactId>jersey-server</artifactId>
+                                    <version>${jersey.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>${project.build.directory}/glassfish6/glassfish/modules</outputDirectory>
+                                    <destFileName>jersey-server.jar</destFileName>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.glassfish.jersey.core</groupId>
+                                    <artifactId>jersey-common</artifactId>
+                                    <version>${jersey.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>${project.build.directory}/glassfish6/glassfish/modules</outputDirectory>
+                                    <destFileName>jersey-common.jar</destFileName>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.glassfish.jersey.containers</groupId>
+                                    <artifactId>jersey-container-grizzly2-http</artifactId>
+                                    <version>${jersey.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>${project.build.directory}/glassfish6/glassfish/modules</outputDirectory>
+                                    <destFileName>jersey-container-grizzly2-http.jar</destFileName>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.glassfish.jersey.containers</groupId>
+                                    <artifactId>jersey-container-servlet-core</artifactId>
+                                    <version>${jersey.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>${project.build.directory}/glassfish6/glassfish/modules</outputDirectory>
+                                    <destFileName>jersey-container-servlet-core.jar</destFileName>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.glassfish.jersey.containers</groupId>
+                                    <artifactId>jersey-container-servlet</artifactId>
+                                    <version>${jersey.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>${project.build.directory}/glassfish6/glassfish/modules</outputDirectory>
+                                    <destFileName>jersey-container-servlet.jar</destFileName>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.glassfish.jersey.media</groupId>
+                                    <artifactId>jersey-media-sse</artifactId>
+                                    <version>${jersey.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>${project.build.directory}/glassfish6/glassfish/modules</outputDirectory>
+                                    <destFileName>jersey-media-sse.jar</destFileName>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.glassfish.jersey.media</groupId>
+                                    <artifactId>jersey-media-json-binding</artifactId>
+                                    <version>${jersey.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>${project.build.directory}/glassfish6/glassfish/modules</outputDirectory>
+                                    <destFileName>jersey-media-json-binding.jar</destFileName>
+                                </artifactItem>
+                                 <artifactItem>
+                                    <groupId>jakarta.ws.rs</groupId>
+                                    <artifactId>jakarta.ws.rs-api</artifactId>
+                                    <version>${jakarta.rest.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>${project.build.directory}/glassfish6/glassfish/modules</outputDirectory>
+                                    <destFileName>jakarta.ws.rs-api.jar</destFileName>
+                                </artifactItem>
+                            </artifactItems>
                         </configuration>
                     </execution>
                 </executions>