Repository: eclipse/microprofile-lra
Pull request #158 (2019-05-27 14:04:34)

TCK participant metrics refactoring
Refactoring of TCK participant metrics (counters of Compensate, Complete,...) to CDI bean instead of JAX-RS. This removes duplication of counters tracking in individual participant resources and as CDI service can be injected to both resources and tests this also lowers the number of JAX-RS calls.

mmusgrov: @xstefank It looks good from an initial skim - I will try to find the time tomorrow to review it in detail.
xstefank: > Looks good but why didn't you also applying the same pattern [of using metrics] to the LraController and ParticipatingTckResource resource classes?

Sorry, the result of doing multiple things at the same time. I will add them asap. Thanks for the review!
xstefank: @mmusgrov updated

Patch:
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/ContextTckResource.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/ContextTckResource.java
index 75729e1..9602ab6 100644
--- a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/ContextTckResource.java
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/ContextTckResource.java
@@ -26,17 +26,19 @@ import org.eclipse.microprofile.lra.annotation.ParticipantStatus;
 import org.eclipse.microprofile.lra.annotation.Status;
 import org.eclipse.microprofile.lra.annotation.ws.rs.LRA;
 import org.eclipse.microprofile.lra.annotation.ws.rs.Leave;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricService;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricType;
 
 import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.HeaderParam;
 import javax.ws.rs.NotFoundException;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.client.ClientBuilder;
 import javax.ws.rs.client.Entity;
@@ -46,16 +48,11 @@ import javax.ws.rs.container.Suspended;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
-import java.util.AbstractMap;
-import java.util.HashMap;
-import java.util.Map;
+import java.net.URI;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionStage;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 import static javax.ws.rs.core.Response.Status.NOT_FOUND;
 import static org.eclipse.microprofile.lra.annotation.ws.rs.LRA.LRA_HTTP_CONTEXT_HEADER;
@@ -100,53 +97,8 @@ public class ContextTckResource {
 
     private ExecutorService excecutorService;
 
-    /**
-     * A class to hold all of the metrics gathered in the context of a single LRA.
-     * We need stats per LRA since a misbehaving test may leave an LRA in need of
-     * recovery which means that the compensate/complete call will continue to be
-     * called when subsequent tests run - ie it is not possible to fully tear down
-     * a failing test.
-     */
-    private static class LRAMetric {
-        String lraId;
-        Map<String, AtomicInteger> metrics = Stream.of(
-                new AbstractMap.SimpleEntry<>(LRA.Type.NESTED.name(), new AtomicInteger(0)),
-                new AbstractMap.SimpleEntry<>(Complete.class.getName(), new AtomicInteger(0)),
-                new AbstractMap.SimpleEntry<>(Compensate.class.getName(), new AtomicInteger(0)),
-                new AbstractMap.SimpleEntry<>(Status.class.getName(), new AtomicInteger(0)),
-                new AbstractMap.SimpleEntry<>(Forget.class.getName(), new AtomicInteger(0)))
-                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
-
-        LRAMetric(String lraId) {
-            this.lraId = lraId;
-        }
-
-        void increment(String metric) {
-            if (metrics.containsKey(metric)) {
-                metrics.get(metric).incrementAndGet();
-            }
-        }
-
-        int get(String metric) {
-            if (metrics.containsKey(metric)) {
-                return metrics.get(metric).get();
-            }
-
-            return -1;
-        }
-
-        void clear() {
-            metrics.forEach((k, v) -> v.set(0));
-        }
-    }
-
-    // maintain metrics on a per LRA basis
-    private Map<String, LRAMetric> metrics = new HashMap<>();
-
-    private void incrementMetric(String name, String lraId) {
-        metrics.putIfAbsent(lraId, new LRAMetric(lraId));
-        metrics.get(lraId).increment(name);
-    }
+    @Inject
+    private LRAMetricService lraMetricService;
 
     /**
      * An enum which controls the behaviour of participant when the
@@ -200,7 +152,7 @@ public class ContextTckResource {
         endPhase = EndPhase.SUCCESS;
         endPhaseStatus = Response.Status.OK;
 
-        metrics.clear();
+        lraMetricService.clear();
 
         return Response.ok().build();
     }
@@ -321,23 +273,6 @@ public class ContextTckResource {
         return response;
     }
 
-    /**
-     * Query the current value of a metric in the context of an LRA
-     * @param lraId the LRA that owns the metric
-     * @param metric the name of the metric
-     * @return the current value of the metric
-     */
-    @GET
-    @Path(METRIC_PATH + "/{metric}")
-    public Response count(@HeaderParam(LRA_TCK_HTTP_CONTEXT_HEADER) String lraId,
-                          @PathParam("metric") String metric) {
-        if (metrics.containsKey(lraId)) {
-            return Response.ok(metrics.get(lraId).get(metric)).build();
-        } else {
-            return Response.ok(-1).build();
-        }
-    }
-
     @Leave
     @PUT
     @Path(LEAVE_PATH)
@@ -348,12 +283,12 @@ public class ContextTckResource {
     @PUT
     @Path("/compensate")
     @Compensate
-    public Response compensateWork(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) String lraId,
-                                   @HeaderParam(LRA_HTTP_PARENT_CONTEXT_HEADER) String parent)
+    public Response compensateWork(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) URI lraId,
+                                   @HeaderParam(LRA_HTTP_PARENT_CONTEXT_HEADER) URI parent)
             throws NotFoundException {
-        incrementMetric(Compensate.class.getName(), lraId);
+        lraMetricService.incrementMetric(LRAMetricType.COMPENSATE, lraId);
         if (parent != null) {
-            incrementMetric(LRA.Type.NESTED.name(), parent);
+            lraMetricService.incrementMetric(LRAMetricType.NESTED, parent);
         }
 
         return getEndPhaseResponse(false);
@@ -362,12 +297,12 @@ public class ContextTckResource {
     @PUT
     @Path("/complete")
     @Complete
-    public Response completeWork(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) String lraId,
-                                 @HeaderParam(LRA_HTTP_PARENT_CONTEXT_HEADER) String parent)
+    public Response completeWork(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) URI lraId,
+                                 @HeaderParam(LRA_HTTP_PARENT_CONTEXT_HEADER) URI parent)
             throws NotFoundException {
-        incrementMetric(Complete.class.getName(), lraId);
+        lraMetricService.incrementMetric(LRAMetricType.COMPLETE, lraId);
         if (parent != null) {
-            incrementMetric(LRA.Type.NESTED.name(), parent);
+            lraMetricService.incrementMetric(LRAMetricType.NESTED, parent);
         }
 
         return getEndPhaseResponse(true);
@@ -376,11 +311,11 @@ public class ContextTckResource {
     @Status
     @GET
     @Path(STATUS_PATH)
-    public Response status(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) String lraId,
-                           @HeaderParam(LRA_HTTP_PARENT_CONTEXT_HEADER) String parent) {
-        incrementMetric(Status.class.getName(), lraId);
+    public Response status(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) URI lraId,
+                           @HeaderParam(LRA_HTTP_PARENT_CONTEXT_HEADER) URI parent) {
+        lraMetricService.incrementMetric(LRAMetricType.STATUS, lraId);
         if (parent != null) {
-            incrementMetric(LRA.Type.NESTED.name(), parent);
+            lraMetricService.incrementMetric(LRAMetricType.NESTED, parent);
         }
 
         return Response.status(endPhaseStatus).entity(status.name()).build();
@@ -389,11 +324,11 @@ public class ContextTckResource {
     @Forget
     @DELETE
     @Path("/forget")
-    public Response forget(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) String lraId,
-                           @HeaderParam(LRA_HTTP_PARENT_CONTEXT_HEADER) String parent) {
-        incrementMetric(Forget.class.getName(), lraId);
+    public Response forget(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) URI lraId,
+                           @HeaderParam(LRA_HTTP_PARENT_CONTEXT_HEADER) URI parent) {
+        lraMetricService.incrementMetric(LRAMetricType.FORGET, lraId);
         if (parent != null) {
-            incrementMetric(LRA.Type.NESTED.name(), parent);
+            lraMetricService.incrementMetric(LRAMetricType.NESTED, parent);
         }
 
         return Response.status(endPhaseStatus).entity(status.name()).build();
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraCancelOnController.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraCancelOnController.java
index 90284ac..5833b64 100644
--- a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraCancelOnController.java
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraCancelOnController.java
@@ -24,7 +24,6 @@ import static org.eclipse.microprofile.lra.annotation.ws.rs.LRA.LRA_HTTP_CONTEXT
 import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URL;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -35,10 +34,8 @@ import javax.ws.rs.HeaderParam;
 import javax.ws.rs.NotFoundException;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
 import javax.ws.rs.client.Client;
 import javax.ws.rs.client.ClientBuilder;
-import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.Response.Status.Family;
@@ -48,21 +45,21 @@ import org.eclipse.microprofile.lra.annotation.Complete;
 import org.eclipse.microprofile.lra.annotation.ws.rs.LRA;
 import org.eclipse.microprofile.lra.annotation.ws.rs.LRA.Type;
 import org.eclipse.microprofile.lra.tck.LraTckConfigBean;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricService;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricType;
 
 @ApplicationScoped
 @Path(LraCancelOnController.LRA_CANCEL_ON_CONTROLLER_PATH)
 public class LraCancelOnController {
     private static final Logger LOGGER = Logger.getLogger(LraCancelOnController.class.getName());
     public static final String LRA_CANCEL_ON_CONTROLLER_PATH = "lracontroller-cancelon";
-    public static final String COMPLETED_COUNT_PATH = "completed";
-    public static final String COMPENSATED_COUNT_PATH = "compensated";
-
-    private final AtomicInteger completedCount = new AtomicInteger(0);
-    private final AtomicInteger compensatedCount = new AtomicInteger(0);
 
     @Inject
     private LraTckConfigBean config;
 
+    @Inject
+    private LRAMetricService lraMetricService;
+
     public static final String CANCEL_ON_FAMILY_DEFAULT_4XX = "cancelOnFamilyDefault4xx";
     /**
      * Default return status for cancelling LRA is <code>4xx</code> and <code>5xx</code>
@@ -71,8 +68,8 @@ public class LraCancelOnController {
     @GET
     @Path(CANCEL_ON_FAMILY_DEFAULT_4XX)
     @LRA(value = Type.REQUIRED)
-    public Response cancelOnFamilyDefault4xx() {
-        return Response.status(Status.BAD_REQUEST).build();
+    public Response cancelOnFamilyDefault4xx(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) String lraId) {
+        return Response.status(Status.BAD_REQUEST).entity(lraId).build();
     }
 
     public static final String CANCEL_ON_FAMILY_DEFAULT_5XX = "cancelOnFamilyDefault5xx";
@@ -83,8 +80,8 @@ public class LraCancelOnController {
     @GET
     @Path(CANCEL_ON_FAMILY_DEFAULT_5XX)
     @LRA(value = Type.REQUIRED)
-    public Response cancelOnFamilyDefault5xx() {
-        return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+    public Response cancelOnFamilyDefault5xx(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) String lraId) {
+        return Response.status(Status.INTERNAL_SERVER_ERROR).entity(lraId).build();
     }
 
     public static final String CANCEL_ON_FAMILY_3XX = "cancelOnFamily3xx";
@@ -97,8 +94,8 @@ public class LraCancelOnController {
     @Path(CANCEL_ON_FAMILY_3XX)
     @LRA(value = Type.REQUIRES_NEW,
             cancelOnFamily = Family.REDIRECTION)
-    public Response cancelOnFamily3xx() {
-        return Response.status(Status.SEE_OTHER).build();
+    public Response cancelOnFamily3xx(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) String lraId) {
+        return Response.status(Status.SEE_OTHER).entity(lraId).build();
     }
 
     public static final String CANCEL_ON_301 = "cancelOn301";
@@ -111,8 +108,8 @@ public class LraCancelOnController {
     @Path(CANCEL_ON_301)
     @LRA(value = Type.REQUIRES_NEW,
         cancelOn = {Status.MOVED_PERMANENTLY})
-    public Response cancelOn301() {
-        return Response.status(Status.MOVED_PERMANENTLY).build();
+    public Response cancelOn301(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) String lraId) {
+        return Response.status(Status.MOVED_PERMANENTLY).entity(lraId).build();
     }
 
     public static final String NOT_CANCEL_ON_FAMILY_5XX = "notCancelOnFamily5xx";
@@ -126,8 +123,8 @@ public class LraCancelOnController {
     @Path(NOT_CANCEL_ON_FAMILY_5XX)
     @LRA(value = Type.REQUIRES_NEW,
             cancelOnFamily = {Family.CLIENT_ERROR})
-    public Response notCancelOnFamily5xx() {
-        return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+    public Response notCancelOnFamily5xx(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) String lraId) {
+        return Response.status(Status.INTERNAL_SERVER_ERROR).entity(lraId).build();
     }
 
     public static final String CANCEL_FROM_REMOTE_CALL = "cancelFromRemoteCall";
@@ -140,10 +137,10 @@ public class LraCancelOnController {
      * <p>
      * The remote REST call invokes the same controller class {@link LraCancelOnController}
      * That assumes the call to the representative of the same LRA participant
-     * as it's already enlisted by the method {@link #cancelFromRemoteCall()} invoked by the test.
+     * as it's already enlisted by the method {@link #cancelFromRemoteCall(String)} invoked by the test.
      * Because the specification mandates that the same participant can be enlisted
      * only once per LRA instance then
-     * the {@link Compensate} method {@link #compensateWork(String, String)}
+     * the {@link Compensate} method {@link #compensateWork(URI, String)}
      * will be called only once for the test invocation.
      * </p>
      * @return JAX-RS response
@@ -151,7 +148,7 @@ public class LraCancelOnController {
     @GET
     @Path(CANCEL_FROM_REMOTE_CALL)
     @LRA(value = Type.REQUIRES_NEW)
-    public Response cancelFromRemoteCall() {
+    public Response cancelFromRemoteCall(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) String lraId) {
         Client client = ClientBuilder.newClient();
         try {
             Response response = client
@@ -163,24 +160,24 @@ public class LraCancelOnController {
         } catch (MalformedURLException murle) {
             LOGGER.log(Level.SEVERE, "Cannot create url from string '"
                     + config.tckSuiteBaseUrl() + "'", murle);
-            return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+            return Response.status(Status.INTERNAL_SERVER_ERROR).entity(lraId).build();
         } finally {
             client.close();
         }
-        return Response.ok().build();
+        return Response.ok(lraId).build();
     }
 
 
     @PUT
     @Path("/complete")
     @Complete
-    public Response completeWork(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) String lraId)
+    public Response completeWork(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) URI lraId)
         throws NotFoundException {
         if(lraId == null) {
             throw new NullPointerException("lraId can't be null as it should be invoked with the context");
         }
 
-        completedCount.incrementAndGet();
+        lraMetricService.incrementMetric(LRAMetricType.COMPLETE, lraId);
 
         LOGGER.info(String.format("LRA id '%s' was completed", lraId));
         return Response.ok().build();
@@ -189,29 +186,15 @@ public class LraCancelOnController {
     @PUT
     @Path("/compensate")
     @Compensate
-    public Response compensateWork(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) String lraId, String userData)
+    public Response compensateWork(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) URI lraId, String userData)
         throws NotFoundException {
         if(lraId == null) {
             throw new NullPointerException("lraId can't be null as it should be invoked with the context");
         }
 
-        compensatedCount.incrementAndGet();
+        lraMetricService.incrementMetric(LRAMetricType.COMPENSATE, lraId);
 
         LOGGER.info(String.format("LRA id '%s' was compensated", lraId));
         return Response.ok().build();
     }
-
-    @GET
-    @Path(COMPLETED_COUNT_PATH)
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response completed() {
-        return Response.ok(completedCount.toString()).build();
-    }
-
-    @GET
-    @Path(COMPENSATED_COUNT_PATH)
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response compensated() {
-        return Response.ok(compensatedCount.toString()).build();
-    }
 }
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraController.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraController.java
index 1501f34..9241db2 100644
--- a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraController.java
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraController.java
@@ -29,6 +29,8 @@ import org.eclipse.microprofile.lra.annotation.Complete;
 import org.eclipse.microprofile.lra.annotation.ws.rs.Leave;
 import org.eclipse.microprofile.lra.annotation.Status;
 import org.eclipse.microprofile.lra.annotation.ParticipantStatus;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricService;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricType;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
@@ -53,11 +55,9 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
-import java.net.URISyntaxException;
 import java.net.URLDecoder;
 import java.time.temporal.ChronoUnit;
 import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.IntStream;
@@ -78,15 +78,15 @@ public class LraController {
 
     private static final String MISSING_LRA_DATA = "Missing LRA data";
 
-    private static final AtomicInteger COMPLETED_COUNT = new AtomicInteger(0);
-    private static final AtomicInteger COMPENSATED_COUNT = new AtomicInteger(0);
-
     @Context
     private UriInfo context;
 
     @Inject
     private ActivityStorage activityStore;
 
+    @Inject
+    private LRAMetricService lraMetricService;
+
     /**
      * Performing a GET on the participant URL will return the current status of the
      * participant {@link ParticipantStatus}, or 404 if the participant is no longer present.
@@ -142,7 +142,7 @@ public class LraController {
     @Complete
     public Response completeWork(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) String lraId, String userData)
         throws NotFoundException {
-        COMPLETED_COUNT.incrementAndGet();
+        lraMetricService.incrementMetric(LRAMetricType.COMPLETE, URI.create(lraId), LraController.class.getName());
 
         assertHeaderPresent(lraId); // the TCK expects the coordinator to invoke @Complete methods
 
@@ -174,7 +174,7 @@ public class LraController {
 
         assertHeaderPresent(lraId); // the TCK expects the coordinator to invoke @Compensate methods
 
-        COMPENSATED_COUNT.incrementAndGet();
+        lraMetricService.incrementMetric(LRAMetricType.COMPENSATE, URI.create(lraId), LraController.class.getName());
 
         Activity activity = activityStore.getActivityAndAssertExistence(lraId, context);
 
@@ -200,7 +200,7 @@ public class LraController {
     @Produces(MediaType.APPLICATION_JSON)
     @Forget
     public Response forgetWork(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) String lraId) {
-        COMPLETED_COUNT.incrementAndGet();
+        lraMetricService.incrementMetric(LRAMetricType.COMPLETE, URI.create(lraId), LraController.class.getName());
 
         assertHeaderPresent(lraId); // the TCK expects the coordinator to invoke @Forget methods
 
@@ -389,22 +389,6 @@ public class LraController {
         return Response.ok(results.size()).build();
     }
 
-    @GET
-    @Path("/completedactivitycount")
-    @Produces(MediaType.APPLICATION_JSON)
-    @LRA(LRA.Type.NOT_SUPPORTED)
-    public Response getCompletedCount() {
-        return Response.ok(COMPLETED_COUNT.get()).build();
-    }
-
-    @GET
-    @Path("/compensatedactivitycount")
-    @Produces(MediaType.APPLICATION_JSON)
-    @LRA(LRA.Type.NOT_SUPPORTED)
-    public Response getCompensatedCount() {
-        return Response.ok(COMPENSATED_COUNT.get()).build();
-    }
-
     @GET
     @Path("/timeLimit")
     @Produces(MediaType.APPLICATION_JSON)
@@ -419,7 +403,7 @@ public class LraController {
         } catch (InterruptedException e) {
             LOGGER.log(Level.FINE, "Interrupted because time limit elapsed", e);
         }
-        return Response.status(Response.Status.OK).entity(Entity.text("Simulate business logic timeoout")).build();
+        return Response.status(Response.Status.OK).entity(lraId).build();
     }
 
     /**
@@ -497,16 +481,6 @@ public class LraController {
         return ParticipantStatus.Compensated.name();
     }
 
-    private static URI lraToURI(String lraId, String errorMessage) {
-        try {
-            return new URI(lraId);
-        } catch (URISyntaxException e) {
-            LOGGER.log(Level.WARNING, "Can't construct URI from LRA id '" + lraId + "'", e);
-            throw new GenericLRAException(null, Response.Status.BAD_REQUEST.getStatusCode(),
-                    errorMessage + ": LRA id '" + lraId + "'", e);
-        }
-    }
-
     private void assertHeaderPresent(String lraId) {
         if (lraId == null) {
             throw new InvalidLRAIdException(null,
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/ParticipatingTckResource.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/ParticipatingTckResource.java
index 2b22970..4238d4a 100644
--- a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/ParticipatingTckResource.java
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/ParticipatingTckResource.java
@@ -23,19 +23,20 @@ import org.eclipse.microprofile.lra.annotation.Compensate;
 import org.eclipse.microprofile.lra.annotation.Complete;
 import org.eclipse.microprofile.lra.annotation.ws.rs.LRA;
 import org.eclipse.microprofile.lra.annotation.ws.rs.Leave;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricService;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricType;
 
 import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
 import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.HeaderParam;
 import javax.ws.rs.NotFoundException;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.net.URI;
 import java.util.logging.Logger;
 
 import static org.eclipse.microprofile.lra.annotation.ws.rs.LRA.LRA_HTTP_CONTEXT_HEADER;
@@ -49,18 +50,16 @@ public class ParticipatingTckResource {
     public static final String JOIN_WITH_EXISTING_LRA_PATH = "/join-with-existing-lra";
     public static final String JOIN_WITH_EXISTING_LRA_PATH2 = "/join-with-existing-lra2";
     public static final String JOIN_WITH_NEW_LRA_PATH = "/join-with-new-LRA";
-    public static final String COMPLETED_CNT_PATH = "/completed-count";
-    public static final String COMPENSATED_CNT_PATH = "/compensated-count";
     public static final String LEAVE_PATH = "/leave";
     public static final String ACCEPT_PATH = "/accept";
 
     public static final String RECOVERY_PARAM = "recoveryCount";
 
-    private static final AtomicInteger COMPLETED_COUNT = new AtomicInteger(0);
-    private static final AtomicInteger COMPENSATED_COUNT = new AtomicInteger(0);
-
     private int recoveryPasses = 0;
 
+    @Inject
+    private LRAMetricService lraMetricService;
+
     @PUT
     @Path("/compensate")
     @Compensate
@@ -72,7 +71,7 @@ public class ParticipatingTckResource {
 
         LOGGER.info(String.format("LRA id '%s' was told to compensate", lraId));
 
-        return getEndPhaseResponse(false);
+        return getEndPhaseResponse(false, URI.create(lraId));
     }
 
     @PUT
@@ -86,18 +85,18 @@ public class ParticipatingTckResource {
 
         LOGGER.info(String.format("LRA id '%s' was told to complete", lraId));
 
-        return getEndPhaseResponse(true);
+        return getEndPhaseResponse(true, URI.create(lraId));
     }
 
-    private Response getEndPhaseResponse(boolean complete) {
+    private Response getEndPhaseResponse(boolean complete, URI lraId) {
         if (--recoveryPasses > 0) {
             return Response.accepted().build();
         }
 
         if (complete) {
-            COMPLETED_COUNT.incrementAndGet();
+            lraMetricService.incrementMetric(LRAMetricType.COMPLETE, lraId, ParticipatingTckResource.class.getName());
         } else {
-            COMPENSATED_COUNT.incrementAndGet();
+            lraMetricService.incrementMetric(LRAMetricType.COMPENSATE, lraId, ParticipatingTckResource.class.getName());
         }
 
         return Response.ok().build();
@@ -126,22 +125,6 @@ public class ParticipatingTckResource {
         return Response.ok().build();
     }
 
-    @GET
-    @Path(COMPLETED_CNT_PATH)
-    @Produces(MediaType.APPLICATION_JSON)
-    @LRA(LRA.Type.NOT_SUPPORTED)
-    public Response getCompletedCount() {
-        return Response.ok(COMPLETED_COUNT.get()).build();
-    }
-
-    @GET
-    @Path(COMPENSATED_CNT_PATH)
-    @Produces(MediaType.APPLICATION_JSON)
-    @LRA(LRA.Type.NOT_SUPPORTED)
-    public Response getCompensatedCount() {
-        return Response.ok(COMPENSATED_COUNT.get()).build();
-    }
-
     // if this resource path is invoked outside of a LRA then, since this JAX-RS resoruce is annotated
     // as a participant, the implementation MUST report a PRECONDITION_FAILED status
     @PUT
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/nonjaxrs/valid/ValidLRACSParticipant.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/nonjaxrs/valid/ValidLRACSParticipant.java
index 3b5209d..3de6392 100644
--- a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/nonjaxrs/valid/ValidLRACSParticipant.java
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/nonjaxrs/valid/ValidLRACSParticipant.java
@@ -24,27 +24,24 @@ import org.eclipse.microprofile.lra.annotation.Complete;
 import org.eclipse.microprofile.lra.annotation.ParticipantStatus;
 import org.eclipse.microprofile.lra.annotation.Status;
 import org.eclipse.microprofile.lra.annotation.ws.rs.LRA;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricService;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricType;
 
 import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
 import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.HeaderParam;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import java.net.URI;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionStage;
-import java.util.concurrent.atomic.AtomicInteger;
 
 import static org.eclipse.microprofile.lra.tck.participant.api.ParticipatingTckResource.ACCEPT_PATH;
 import static org.eclipse.microprofile.lra.tck.participant.api.ParticipatingTckResource.RECOVERY_PARAM;
-import static org.eclipse.microprofile.lra.tck.participant.nonjaxrs.valid.ValidLRAParticipant.COMPENSATED_COUNT_PATH;
-import static org.eclipse.microprofile.lra.tck.participant.nonjaxrs.valid.ValidLRAParticipant.COMPLETED_COUNT_PATH;
-import static org.eclipse.microprofile.lra.tck.participant.nonjaxrs.valid.ValidLRAParticipant.STATUS_COUNT_PATH;
 
 /**
  * Valid participant resource containing async non-JAX-RS participant methods with 
@@ -57,25 +54,24 @@ public class ValidLRACSParticipant {
     public static final String ROOT_PATH = "valid-cs-participant1";
     public static final String ENLIST_WITH_COMPLETE = "enlist-complete";
     public static final String ENLIST_WITH_COMPENSATE = "enlist-compensate";
-
-    private final AtomicInteger completedCount = new AtomicInteger(0);
-    private final AtomicInteger compensatedCount = new AtomicInteger(0);
-    private final AtomicInteger statusCount = new AtomicInteger(0);
     
     private int recoveryPasses;
 
+    @Inject
+    private LRAMetricService lraMetricService;
+
     @GET
     @Path(ENLIST_WITH_COMPLETE)
     @LRA(value = LRA.Type.REQUIRED)
     public Response enlistWithComplete(@HeaderParam(LRA.LRA_HTTP_CONTEXT_HEADER) String lraId) {
-        return Response.ok().build();
+        return Response.ok(lraId).build();
     }
     
     @GET
     @Path(ENLIST_WITH_COMPENSATE)
     @LRA(value = LRA.Type.REQUIRED, cancelOn = Response.Status.INTERNAL_SERVER_ERROR)
     public Response enlistWithCompensate(@HeaderParam(LRA.LRA_HTTP_CONTEXT_HEADER) String lraId) {
-        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(lraId).build();
     }
 
     @Compensate
@@ -83,7 +79,7 @@ public class ValidLRACSParticipant {
         assert lraId != null;
         
         return CompletableFuture.runAsync(() -> {
-            compensatedCount.incrementAndGet();
+            lraMetricService.incrementMetric(LRAMetricType.COMPENSATE, lraId);
             
             simulateLongRunningCompensation();
         });
@@ -94,7 +90,7 @@ public class ValidLRACSParticipant {
         assert lraId != null;
         
         return CompletableFuture.supplyAsync(() -> {
-            completedCount.incrementAndGet();
+            lraMetricService.incrementMetric(LRAMetricType.COMPLETE, lraId);
             
             simulateLongRunningCompensation();
             return Response.accepted().build(); // Completing
@@ -106,7 +102,7 @@ public class ValidLRACSParticipant {
         assert lraId != null;
         
         return CompletableFuture.supplyAsync(() -> {
-            statusCount.incrementAndGet();
+            lraMetricService.incrementMetric(LRAMetricType.STATUS, lraId);
             
             simulateLongRunningCompensation();
             return ParticipantStatus.Completed;
@@ -120,28 +116,7 @@ public class ValidLRACSParticipant {
             e.printStackTrace();
         }
     }
-
-    @GET
-    @Path(COMPLETED_COUNT_PATH)
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response completed() {
-        return Response.ok(completedCount.toString()).build();
-    }
     
-    @GET
-    @Path(COMPENSATED_COUNT_PATH)
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response compensated() {
-        return Response.ok(compensatedCount.toString()).build();
-    }
-
-    @GET
-    @Path(STATUS_COUNT_PATH)
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response statusCount() {
-        return Response.ok(statusCount.toString()).build();
-    }
-
     @PUT
     @Path(ACCEPT_PATH)
     @LRA(value = LRA.Type.REQUIRES_NEW)
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/nonjaxrs/valid/ValidLRAParticipant.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/nonjaxrs/valid/ValidLRAParticipant.java
index fd3a1f8..4bb1aa6 100644
--- a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/nonjaxrs/valid/ValidLRAParticipant.java
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/nonjaxrs/valid/ValidLRAParticipant.java
@@ -26,19 +26,20 @@ import org.eclipse.microprofile.lra.annotation.ParticipantStatus;
 import org.eclipse.microprofile.lra.annotation.Status;
 import org.eclipse.microprofile.lra.annotation.ws.rs.LRA;
 import org.eclipse.microprofile.lra.annotation.ws.rs.LRA.Type;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricService;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricType;
 
 import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
 import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import java.net.URI;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Logger;
 
 import static org.eclipse.microprofile.lra.tck.participant.api.ParticipatingTckResource.ACCEPT_PATH;
@@ -53,24 +54,18 @@ public class ValidLRAParticipant {
     private static final Logger LOGGER = Logger.getLogger(ValidLRAParticipant.class.getName());
     
     public static final String RESOURCE_PATH = "valid-nonjaxrs";
-    public static final String COMPLETED_COUNT_PATH = "completed";
-    public static final String COMPENSATED_COUNT_PATH = "compensated";
-    public static final String STATUS_COUNT_PATH = "status";
-    public static final String FORGET_COUNT_PATH = "forget";
-
-    private final AtomicInteger completedCount = new AtomicInteger(0);
-    private final AtomicInteger compensatedCount = new AtomicInteger(0);
-    private final AtomicInteger statusCount = new AtomicInteger(0);
-    private final AtomicInteger forgetCount = new AtomicInteger(0);
-
     public static final String ENLIST_WITH_COMPLETE = "nonjaxrs-enlist-complete";
+    
     private int recoveryPasses;
 
+    @Inject
+    private LRAMetricService lraMetricService;
+
     @GET
     @Path(ENLIST_WITH_COMPLETE)
     @LRA(value = Type.REQUIRED)
-    public Response enlistWithComplete() {
-        return Response.ok().build();
+    public Response enlistWithComplete(@HeaderParam(LRA.LRA_HTTP_CONTEXT_HEADER) String lraId) {
+        return Response.ok(lraId).build();
     }
 
     public static final String ENLIST_WITH_COMPENSATE = "nonjaxrs-enlist-compensate";
@@ -78,8 +73,8 @@ public class ValidLRAParticipant {
     @GET
     @Path(ENLIST_WITH_COMPENSATE)
     @LRA(value = Type.REQUIRED, cancelOn = Response.Status.INTERNAL_SERVER_ERROR)
-    public Response enlistWithCompensate() {
-        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+    public Response enlistWithCompensate(@HeaderParam(LRA.LRA_HTTP_CONTEXT_HEADER) String lraId) {
+        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(lraId).build();
     }
 
 
@@ -87,7 +82,7 @@ public class ValidLRAParticipant {
     public void completeWithException(URI lraId, URI parentId) {
         verifyLRAId(lraId);
 
-        completedCount.incrementAndGet();
+        lraMetricService.incrementMetric(LRAMetricType.COMPLETE, lraId);
 
         LOGGER.fine(String.format("LRA id '%s' was completed", lraId));
         throw new WebApplicationException(Response.ok().build());
@@ -97,7 +92,7 @@ public class ValidLRAParticipant {
     public ParticipantStatus compensate(URI lraId) {
         verifyLRAId(lraId);
 
-        compensatedCount.incrementAndGet();
+        lraMetricService.incrementMetric(LRAMetricType.COMPENSATE, lraId);
 
         LOGGER.fine(String.format("LRA id '%s' was compensated", lraId));
         return ParticipantStatus.Compensating;
@@ -107,7 +102,7 @@ public class ValidLRAParticipant {
     public Response status(URI lraId) {
         verifyLRAId(lraId);
 
-        statusCount.incrementAndGet();
+        lraMetricService.incrementMetric(LRAMetricType.STATUS, lraId);
 
         LOGGER.fine(String.format("LRA id '%s' status called, return FailedToCompensate to get @Forget called", lraId));
         return Response.ok(ParticipantStatus.FailedToCompensate).build();
@@ -117,7 +112,7 @@ public class ValidLRAParticipant {
     public void forget(URI lraId) {
         verifyLRAId(lraId);
 
-        forgetCount.incrementAndGet();
+        lraMetricService.incrementMetric(LRAMetricType.FORGET, lraId);
 
         LOGGER.fine(String.format("LRA id '%s' forget called", lraId));
     }
@@ -128,34 +123,6 @@ public class ValidLRAParticipant {
         }
     }
 
-    @GET
-    @Path(COMPLETED_COUNT_PATH)
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response completed() {
-        return Response.ok(completedCount.toString()).build();
-    }
-
-    @GET
-    @Path(COMPENSATED_COUNT_PATH)
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response compensated() {
-        return Response.ok(compensatedCount.toString()).build();
-    }
-
-    @GET
-    @Path(STATUS_COUNT_PATH)
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response statusCount() {
-        return Response.ok(statusCount.toString()).build();
-    }
-
-    @GET
-    @Path(FORGET_COUNT_PATH)
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response forgetCount() {
-        return Response.ok(forgetCount.toString()).build();
-    }
-
     @PUT
     @Path(ACCEPT_PATH)
     @LRA(value = LRA.Type.REQUIRES_NEW)
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/service/LRAMetricService.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/service/LRAMetricService.java
new file mode 100644
index 0000000..3050f1a
--- /dev/null
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/service/LRAMetricService.java
@@ -0,0 +1,100 @@
+/*
+ *******************************************************************************
+ * Copyright (c) 2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+package org.eclipse.microprofile.lra.tck.service;
+
+import javax.enterprise.context.ApplicationScoped;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@ApplicationScoped
+public class LRAMetricService {
+
+    private static final String ALL = "all-participants";
+    
+    // maintain metrics on a per LRA basis
+    private Map<URI, Map<String, LRAMetric>> metrics = new HashMap<>();
+    
+    public void incrementMetric(LRAMetricType name, URI lraId) {
+        incrementMetric(name, lraId, ALL);
+    }
+    
+    public void incrementMetric(LRAMetricType name, URI lraId, String participant) {
+        metrics.putIfAbsent(lraId, new HashMap<>());
+        metrics.get(lraId).putIfAbsent(participant, new LRAMetric());
+        metrics.get(lraId).get(participant).increment(name);
+    }
+
+    public int getMetric(LRAMetricType name) {
+        AtomicInteger result = new AtomicInteger();
+
+        metrics.values().forEach(participantMap -> 
+            participantMap.values().forEach(metric -> result.addAndGet(metric.get(name))));
+
+        return result.get();
+    }
+
+    public int getMetric(LRAMetricType name, URI lraId) {
+        return getMetric(name, lraId, ALL);
+    }
+
+    public int getMetric(LRAMetricType metric, URI lraId, String participant) {
+        if (metrics.containsKey(lraId) && metrics.get(lraId).containsKey(participant)) {
+            return metrics.get(lraId).get(participant).get(metric);
+        } else {
+            return -1;
+        }
+    }
+
+    public void clear() {
+        metrics.clear();
+    }
+    
+    /**
+     * A class to hold all of the metrics gathered in the context of a single LRA.
+     * We need stats per LRA since a misbehaving test may leave an LRA in need of
+     * recovery which means that the compensate/complete call will continue to be
+     * called when subsequent tests run - ie it is not possible to fully tear down
+     * a failing test.
+     */
+    private static class LRAMetric {
+        Map<LRAMetricType, AtomicInteger> metrics = Arrays.stream(LRAMetricType.values())
+            .collect(Collectors.toMap(Function.identity(), t -> new AtomicInteger(0)));
+
+        void increment(LRAMetricType metric) {
+            if (metrics.containsKey(metric)) {
+                metrics.get(metric).incrementAndGet();
+            }
+        }
+
+        int get(LRAMetricType metric) {
+            if (metrics.containsKey(metric)) {
+                return metrics.get(metric).get();
+            }
+
+            return -1;
+        }
+    }
+
+}
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/service/LRAMetricType.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/service/LRAMetricType.java
new file mode 100644
index 0000000..457dbfd
--- /dev/null
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/service/LRAMetricType.java
@@ -0,0 +1,29 @@
+/*
+ *******************************************************************************
+ * Copyright (c) 2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+package org.eclipse.microprofile.lra.tck.service;
+
+public enum LRAMetricType {
+    
+    COMPENSATE,
+    COMPLETE,
+    STATUS,
+    FORGET,
+    NESTED
+}


Test patch:
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckCancelOnTests.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckCancelOnTests.java
index 06f23e7..b0e71ba 100644
--- a/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckCancelOnTests.java
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckCancelOnTests.java
@@ -19,138 +19,146 @@
  *******************************************************************************/
 package org.eclipse.microprofile.lra.tck;
 
-import static org.eclipse.microprofile.lra.tck.participant.api.LraCancelOnController.LRA_CANCEL_ON_CONTROLLER_PATH;
-import static org.junit.Assert.assertEquals;
-
-import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
-
 import org.eclipse.microprofile.lra.tck.participant.api.LraCancelOnController;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricService;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricType;
 import org.jboss.arquillian.container.test.api.Deployment;
 import org.jboss.arquillian.junit.Arquillian;
 import org.jboss.shrinkwrap.api.spec.WebArchive;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import javax.inject.Inject;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import java.net.URI;
+
+import static org.eclipse.microprofile.lra.tck.participant.api.LraCancelOnController.LRA_CANCEL_ON_CONTROLLER_PATH;
+import static org.junit.Assert.assertEquals;
+
 @RunWith(Arquillian.class)
 public class TckCancelOnTests extends TckTestBase {
-    private int beforeCompletedCount;
-    private int beforeCompensatedCount;
 
+    @Inject
+    private LRAMetricService lraMetricService;
+    
     @Deployment(name = "tcktests-cancelon")
     public static WebArchive deploy() {
         return TckTestBase.deploy(TckCancelOnTests.class.getSimpleName().toLowerCase());
     }
 
-    @Before
-    public void before() {
-        super.before();
-
-        this.beforeCompletedCount = getCompletedCount();
-        this.beforeCompensatedCount = getCompensateCount(false);
-    }
-
     private WebTarget getSuiteTarget() {
         return tckSuiteTarget;
     }
 
     /**
-     * See {@link LraCancelOnController#cancelOnFamilyDefault4xx()}
+     * See {@link LraCancelOnController#cancelOnFamilyDefault4xx(String)}
      */
     @Test
     public void cancelOnFamilyDefault4xx() {
-        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
-                .path(LraCancelOnController.CANCEL_ON_FAMILY_DEFAULT_4XX).request().get();
-        assertEquals("The 400 status response is expected", Status.BAD_REQUEST.getStatusCode(), response.getStatus());
-        assertEquals("After 400 compensate should be invoked", beforeCompensatedCount + 1, getCompensateCount(true));
-        assertEquals("After 400 complete can't be invoked", beforeCompletedCount, getCompletedCount());
+        WebTarget resourcePath = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
+            .path(LraCancelOnController.CANCEL_ON_FAMILY_DEFAULT_4XX);
+        
+        Response response = resourcePath.request().get();
+
+        URI lraId = URI.create(checkStatusReadAndCloseResponse(Status.BAD_REQUEST, response, resourcePath));
+        applyConsistencyDelay();
+        assertEquals("After 400 compensate should be invoked", 
+            1, lraMetricService.getMetric(LRAMetricType.COMPENSATE, lraId));
+        assertEquals("After 400 complete can't be invoked", 
+            0, lraMetricService.getMetric(LRAMetricType.COMPLETE, lraId));
     }
 
     /**
-     * See {@link LraCancelOnController#cancelOnFamilyDefault5xx()}
+     * See {@link LraCancelOnController#cancelOnFamilyDefault5xx(String)}
      */
     @Test
     public void cancelOnFamilyDefault5xx() {
-        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
-                .path(LraCancelOnController.CANCEL_ON_FAMILY_DEFAULT_5XX).request().get();
-        assertEquals("The 500 status response is expected", Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());
-        assertEquals("After 500 compensate should be invoked", beforeCompensatedCount + 1, getCompensateCount(true));
-        assertEquals("After 500 complete can't be invoked", beforeCompletedCount, getCompletedCount());
+        WebTarget resourcePath = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
+            .path(LraCancelOnController.CANCEL_ON_FAMILY_DEFAULT_5XX);
+        
+        Response response = resourcePath.request().get();
+
+        URI lraId = URI.create(checkStatusReadAndCloseResponse(Status.INTERNAL_SERVER_ERROR, response, resourcePath));
+        applyConsistencyDelay();
+        assertEquals("After 500 compensate should be invoked", 
+            1, lraMetricService.getMetric(LRAMetricType.COMPENSATE, lraId));
+        assertEquals("After 500 complete can't be invoked", 
+            0, lraMetricService.getMetric(LRAMetricType.COMPLETE, lraId));
     }
 
     /**
-     * See {@link LraCancelOnController#cancelOnFamily3xx()}
+     * See {@link LraCancelOnController#cancelOnFamily3xx(String)}
      */
     @Test
     public void cancelOnFamily3xx() {
-        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
-                .path(LraCancelOnController.CANCEL_ON_FAMILY_3XX).request().get();
-        assertEquals("The 303 status response is expected", Status.SEE_OTHER.getStatusCode(), response.getStatus());
+        WebTarget resourcePath = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
+            .path(LraCancelOnController.CANCEL_ON_FAMILY_3XX);
+        
+        Response response = resourcePath.request().get();
+
+        URI lraId = URI.create(checkStatusReadAndCloseResponse(Status.SEE_OTHER, response, resourcePath));
+        applyConsistencyDelay();
         assertEquals("After status code 303 is received, compensate should be invoked as set by attribute cancelOnFamily",
-                beforeCompensatedCount + 1, getCompensateCount(true));
+                1, lraMetricService.getMetric(LRAMetricType.COMPENSATE, lraId));
         assertEquals("After status code 303 is received, complete can't be invoked as not defined in annotation @LRA",
-                beforeCompletedCount, getCompletedCount());
+                0, lraMetricService.getMetric(LRAMetricType.COMPLETE, lraId));
     }
 
     /**
-     * See {@link LraCancelOnController#cancelOn301()}
+     * See {@link LraCancelOnController#cancelOn301(String)}
      */
     @Test
     public void cancelOn301() {
-        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
-                .path(LraCancelOnController.CANCEL_ON_301).request().get();
-        assertEquals("The 301 status response is expected", Status.MOVED_PERMANENTLY.getStatusCode(), response.getStatus());
+        WebTarget resourcePath = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
+            .path(LraCancelOnController.CANCEL_ON_301);
+        
+        Response response = resourcePath.request().get();
+
+        URI lraId = URI.create(checkStatusReadAndCloseResponse(Status.MOVED_PERMANENTLY, response, resourcePath));
+        applyConsistencyDelay();
         assertEquals("After status code 301 is received, compensate should be invoked as set by attribute cancelOn",
-                beforeCompensatedCount + 1, getCompensateCount(true));
+                1, lraMetricService.getMetric(LRAMetricType.COMPENSATE, lraId));
         assertEquals("After status code 301 is received, complete can't be invoked as not defined in annotation @LRA",
-                beforeCompletedCount, getCompletedCount());
+                0, lraMetricService.getMetric(LRAMetricType.COMPLETE, lraId));
     }
 
     /**
-     * See {@link LraCancelOnController#notCancelOnFamily5xx()}
+     * See {@link LraCancelOnController#notCancelOnFamily5xx(String)}
      */
     @Test
     public void notCancelOnFamily5xx() {
-        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
-                .path(LraCancelOnController.NOT_CANCEL_ON_FAMILY_5XX).request().get();
-        assertEquals("The 500 status response is expected", Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());
+        WebTarget resourcePath = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
+            .path(LraCancelOnController.NOT_CANCEL_ON_FAMILY_5XX);
+        
+        Response response = resourcePath.request().get();
+
+        URI lraId = URI.create(checkStatusReadAndCloseResponse(Status.INTERNAL_SERVER_ERROR, response, resourcePath));
+        applyConsistencyDelay();
         assertEquals("After status code 500 is received, compensate can't be invoked as default behaviour was changed",
-                beforeCompensatedCount, getCompensateCount(true));
+                0, lraMetricService.getMetric(LRAMetricType.COMPENSATE, lraId));
         assertEquals("After status code 500 is received, complete has to be called as default behaviour was changed",
-                beforeCompletedCount + 1, getCompletedCount());
+                1, lraMetricService.getMetric(LRAMetricType.COMPLETE, lraId));
     }
 
     /**
-     * See {@link LraCancelOnController#cancelFromRemoteCall()}
+     * See {@link LraCancelOnController#cancelFromRemoteCall(String)}
      */
     @Test
     public void cancelFromRemoteCall() {
-        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
-                .path(LraCancelOnController.CANCEL_FROM_REMOTE_CALL).request().get();
-        assertEquals("The 200 status response is expected", Status.OK.getStatusCode(), response.getStatus());
+        WebTarget resourcePath = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
+            .path(LraCancelOnController.CANCEL_FROM_REMOTE_CALL);
+        
+        Response response = resourcePath.request().get();
+
+        URI lraId = URI.create(checkStatusReadAndCloseResponse(Status.OK, response, resourcePath));
+        applyConsistencyDelay();
         // LraCancelOnController enlists twice the same participant, compensate is expected to be called only once
         assertEquals("Status was 200 but compensate should be called as LRA should be cancelled for remotely called participant as well",
-                beforeCompensatedCount + 1, getCompensateCount(true));
+                1, lraMetricService.getMetric(LRAMetricType.COMPENSATE, lraId));
         assertEquals("Even the 200 status was received the remotely called participant should cause the LRA being cancelled",
-                beforeCompletedCount, getCompletedCount());
-    }
-
-    private int getCompletedCount() {
-        // no option to delay the check since all tests call getCompensateCount first
-        // which does have the option to delay
-        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
-                .path(LraCancelOnController.COMPLETED_COUNT_PATH).request().get();
-        return response.readEntity(Integer.class);
-    }
-
-    private int getCompensateCount(boolean delay) {
-        if (delay) {
-            applyConsistencyDelay();
-        }
-        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
-                .path(LraCancelOnController.COMPENSATED_COUNT_PATH).request().get();
-        return Integer.valueOf(response.readEntity(String.class));
+                0, lraMetricService.getMetric(LRAMetricType.COMPLETE, lraId));
     }
 }
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckContextTests.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckContextTests.java
index 9fa6c83..4951706 100644
--- a/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckContextTests.java
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckContextTests.java
@@ -19,13 +19,10 @@
  *******************************************************************************/
 package org.eclipse.microprofile.lra.tck;
 
-import org.eclipse.microprofile.lra.annotation.Compensate;
-import org.eclipse.microprofile.lra.annotation.Complete;
-import org.eclipse.microprofile.lra.annotation.Forget;
 import org.eclipse.microprofile.lra.annotation.ParticipantStatus;
-import org.eclipse.microprofile.lra.annotation.Status;
-import org.eclipse.microprofile.lra.annotation.ws.rs.LRA;
 import org.eclipse.microprofile.lra.tck.participant.api.ContextTckResource;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricService;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricType;
 import org.jboss.arquillian.container.test.api.Deployment;
 import org.jboss.arquillian.junit.Arquillian;
 import org.jboss.shrinkwrap.api.spec.WebArchive;
@@ -33,13 +30,15 @@ import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import javax.inject.Inject;
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.Invocation;
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Response;
 
+import java.net.URI;
+
 import static org.eclipse.microprofile.lra.annotation.ws.rs.LRA.LRA_HTTP_CONTEXT_HEADER;
-import static org.eclipse.microprofile.lra.tck.TckContextTests.HttpMethod.GET;
 import static org.eclipse.microprofile.lra.tck.TckContextTests.HttpMethod.PUT;
 import static org.eclipse.microprofile.lra.tck.participant.api.ContextTckResource.ASYNC_LRA_PATH1;
 import static org.eclipse.microprofile.lra.tck.participant.api.ContextTckResource.ASYNC_LRA_PATH2;
@@ -68,6 +67,9 @@ public class TckContextTests extends TckTestBase {
 
     enum HttpMethod {GET, PUT, POST}
 
+    @Inject
+    private LRAMetricService lraMetricService;
+
     @Deployment(name = "TckContextTests")
     public static WebArchive deploy() {
         return TckTestBase.deploy(TckContextTests.class.getSimpleName().toLowerCase());
@@ -81,20 +83,20 @@ public class TckContextTests extends TckTestBase {
 
     @Test
     public void testBasicContextPropagation() {
-        String lra = invoke(false, NEW_LRA_PATH, PUT, null, 200, ContextTckResource.EndPhase.SUCCESS, 200);
+        URI lra = URI.create(invoke(false, NEW_LRA_PATH, PUT, null, 200, ContextTckResource.EndPhase.SUCCESS, 200));
         invoke(false, REQUIRED_LRA_PATH, PUT, lra, 200, ContextTckResource.EndPhase.SUCCESS, 200);
 
         // verify that the resource was asked to complete
-        String completions = invoke(true, METRIC_PATH + "/" + Complete.class.getName(), GET, lra);
+        int completions = lraMetricService.getMetric(LRAMetricType.COMPLETE, lra);
 
-        assertEquals(testName.getMethodName() + ": Resource was not asked to complete",
-                Integer.toString(1), completions);
+        assertEquals(testName.getMethodName() + ": Resource was not asked to complete", 
+                1, completions);
     }
 
     @Test
     public void testStatus() throws InterruptedException {
         // call a resource that begins and ends an LRA and coerces the resource to return ACCEPTED when asked to complete
-        String lra = invoke(false, REQUIRED_LRA_PATH, PUT, null, 200, ContextTckResource.EndPhase.ACCEPTED, 202);
+        URI lra = URI.create(invoke(false, REQUIRED_LRA_PATH, PUT, null, 200, ContextTckResource.EndPhase.ACCEPTED, 202));
 
         // verify that the resource was asked to complete and is in the state Completing
         String status = invoke(true, STATUS_PATH, HttpMethod.GET, lra, 202, ContextTckResource.EndPhase.SUCCESS, 200);
@@ -114,7 +116,7 @@ public class TckContextTests extends TckTestBase {
     @Test
     public void testLeave() {
         // call a resource that begins but does not end an LRA
-        String lra = invoke(false, NEW_LRA_PATH, PUT, null, 200, ContextTckResource.EndPhase.SUCCESS, 200);
+        URI lra = URI.create(invoke(false, NEW_LRA_PATH, PUT, null, 200, ContextTckResource.EndPhase.SUCCESS, 200));
         // verify that the resource is active
         String status = invoke(false, STATUS_PATH, HttpMethod.GET, lra, 200, ContextTckResource.EndPhase.SUCCESS, 200);
 
@@ -127,28 +129,28 @@ public class TckContextTests extends TckTestBase {
         lraClient.closeLRA(lra);
 
         // verify that the resource was not asked to complete
-        String completions = invoke(true, METRIC_PATH + "/" + Complete.class.getName(), GET, lra);
+        int completions = lraMetricService.getMetric(LRAMetricType.COMPLETE, lra);
 
         assertEquals(testName.getMethodName() + ": Resource left but was still asked to complete",
-                "0", completions);
+                0, completions);
     }
 
     @Test
     public void testForget() throws InterruptedException {
-        String count;
+        int count;
         // call a resource that begins and ends an LRA and coerces the resource to return FAILED when asked to complete
-        String lra = invoke(false, REQUIRED_LRA_PATH, PUT, null, 200, ContextTckResource.EndPhase.FAILED, 500);
+        URI lra = URI.create(invoke(false, REQUIRED_LRA_PATH, PUT, null, 200, ContextTckResource.EndPhase.FAILED, 500));
 
         // trigger a replay attempt
         replayEndPhase(TCK_CONTEXT_RESOURCE_PATH);
 
         // the implementation should have called status which will have returned 500
-        count = invoke(true, METRIC_PATH + "/" + Status.class.getName(), GET, lra);
-        assertEquals(testName.getMethodName() + " resource status should have been called", "1", count);
+        count = lraMetricService.getMetric(LRAMetricType.STATUS, lra);
+        assertEquals(testName.getMethodName() + " resource status should have been called", 1, count);
 
         // the implementation should not call forget until it knows the participant status
-        count = invoke(false, METRIC_PATH + "/" + Forget.class.getName(), GET, lra);
-        assertEquals(testName.getMethodName() + " resource forget should not have been called", "0", count);
+        count = lraMetricService.getMetric(LRAMetricType.FORGET, lra);
+        assertEquals(testName.getMethodName() + " resource forget should not have been called", 0, count);
 
         // clear the fault
         invoke(false, STATUS_PATH, PUT, lra, 200, ContextTckResource.EndPhase.FAILED, 200);
@@ -157,11 +159,11 @@ public class TckContextTests extends TckTestBase {
         replayEndPhase(TCK_CONTEXT_RESOURCE_PATH);
 
         // the implementation should have called status again which will have returned 200
-        count = invoke(false, METRIC_PATH + "/" + Status.class.getName(), GET, lra);
-        assertEquals(testName.getMethodName() + " resource status should have been called again", "2", count);
+        count = lraMetricService.getMetric(LRAMetricType.STATUS, lra);
+        assertEquals(testName.getMethodName() + " resource status should have been called again", 2, count);
         // the implementation should call forget since it knows the participant status
-        count = invoke(false, METRIC_PATH + "/" + Forget.class.getName(), GET, lra);
-        assertEquals(testName.getMethodName() + " resource forget should have been called", "1", count);
+        count = lraMetricService.getMetric(LRAMetricType.FORGET, lra);
+        assertEquals(testName.getMethodName() + " resource forget should have been called", 1, count);
     }
 
     /*
@@ -172,14 +174,14 @@ public class TckContextTests extends TckTestBase {
     @Test
     public void testParentContextAvailable() {
         // start an LRA
-        String topLevelLRA = invoke(false, NEW_LRA_PATH, PUT, null);
+        URI topLevelLRA = URI.create(invoke(false, NEW_LRA_PATH, PUT, null));
         // start a nested LRA
         String result = invoke(false, NESTED_LRA_PATH, PUT, topLevelLRA);
         // the resource method should return the nested LRA and the top level LRA separated by a comma
         assertTrue(result.contains(","));
-        assertEquals(testName.getMethodName() + ": wrong parent LRA", topLevelLRA, result.split(",")[1]);
+        assertEquals(testName.getMethodName() + ": wrong parent LRA", topLevelLRA, URI.create(result.split(",")[1]));
 
-        String nestedLRA = result.split(",")[0];
+        URI nestedLRA = URI.create(result.split(",")[0]);
 
         // end the top level LRA
         invoke(false, REQUIRED_LRA_PATH, PUT, topLevelLRA);
@@ -187,20 +189,19 @@ public class TckContextTests extends TckTestBase {
         // check that the resource was asked to complete twice, one in the context of the nested LRA and a
         // second time in the context of the top level LRA
 
-        String nestedCompletions = invoke(true, METRIC_PATH + "/" + Complete.class.getName(), GET, nestedLRA);
+        int nestedCompletions = lraMetricService.getMetric(LRAMetricType.COMPLETE, nestedLRA);
         assertEquals(testName.getMethodName() + ": resource should have completed for the nested LRA",
-                "1", nestedCompletions);
+                1, nestedCompletions);
 
-        String topLevelCompletions = invoke(false, METRIC_PATH + "/" + Complete.class.getName(), GET, topLevelLRA);
+        int topLevelCompletions = lraMetricService.getMetric(LRAMetricType.COMPLETE, topLevelLRA);
         assertEquals(testName.getMethodName() + ": resource should have completed for the top level LRA",
-                "1", topLevelCompletions);
+                1, topLevelCompletions);
 
         // and validate that the parent LRA header was present when the nested LRA was asked to complete
-        String endCallsWithParentContextHeaderPresent = invoke(false, METRIC_PATH + "/" + LRA.Type.NESTED.name(),
-                GET, topLevelLRA);
+        int endCallsWithParentContextHeaderPresent = lraMetricService.getMetric(LRAMetricType.NESTED, topLevelLRA);
         assertEquals(testName.getMethodName() +
                         ": when the resource was asked to complete a nested LRA the parent context header was missing",
-                "1", endCallsWithParentContextHeaderPresent);
+                1, endCallsWithParentContextHeaderPresent);
     }
 
     // invoke a method in an LRA context which performs various outgoing calls checking that the notion of active context
@@ -212,46 +213,47 @@ public class TckContextTests extends TckTestBase {
 
     @Test
     public void testAsync1Support() {
-        String lra = invoke(false, ASYNC_LRA_PATH1, PUT, null);
+        URI lra = URI.create(invoke(false, ASYNC_LRA_PATH1, PUT, null));
 
         // verify that the resource was asked to complete
-        String completions = invoke(true, METRIC_PATH + "/" + Complete.class.getName(), GET, lra);
+        int completions = lraMetricService.getMetric(LRAMetricType.COMPLETE, lra);
 
         assertEquals(testName.getMethodName() + ": Resource was not asked to complete",
-                Integer.toString(1), completions);
+                1, completions);
     }
 
     @Test
     public void testAsync2Support() {
-        String lra = invoke(false, ASYNC_LRA_PATH2, PUT, null);
+        URI lra = URI.create(invoke(false, ASYNC_LRA_PATH2, PUT, null));
 
         // verify that the resource was asked to complete
-        String completions = invoke(true, METRIC_PATH + "/" + Complete.class.getName(), GET, lra);
+        int completions = lraMetricService.getMetric(LRAMetricType.COMPLETE, lra);
 
         assertEquals(testName.getMethodName() + ": Resource was not asked to complete",
-                Integer.toString(1), completions);
+                1, completions);
     }
 
     @Test
     public void testAsync3Support() {
         // invoke an async resource that throws an exception which cancels the LRA
-        String lra = invoke(true, ASYNC_LRA_PATH3, PUT, null, 404, ContextTckResource.EndPhase.SUCCESS, 200);
+        URI lra = URI.create(invoke(true, ASYNC_LRA_PATH3, PUT, null, 404, 
+            ContextTckResource.EndPhase.SUCCESS, 200));
 
         // verify that the resource was asked to compensate
-        String completions = invoke(true, METRIC_PATH + "/" + Complete.class.getName(), GET, lra);
-        String compensations = invoke(false, METRIC_PATH + "/" + Compensate.class.getName(), GET, lra);
+        int completions = lraMetricService.getMetric(LRAMetricType.COMPLETE, lra);
+        int compensations = lraMetricService.getMetric(LRAMetricType.COMPENSATE, lra);
 
         assertEquals(testName.getMethodName() + ": Resource was asked to complete",
-                Integer.toString(0), completions);
+                0, completions);
         assertEquals(testName.getMethodName() + ": Resource was not asked to compensate",
-                Integer.toString(1), compensations);
+                1, compensations);
     }
 
-    private String invoke(boolean delay, String where, HttpMethod method, String lraContext) {
+    private String invoke(boolean delay, String where, HttpMethod method, URI lraContext) {
         return invoke(delay, where, method, lraContext, 200, ContextTckResource.EndPhase.SUCCESS, 200);
     }
 
-    private String invoke(boolean delay, String where, HttpMethod method, String lraContext, int expectStatus,
+    private String invoke(boolean delay, String where, HttpMethod method, URI lraContext, int expectStatus,
                           ContextTckResource.EndPhase finishWith, int finishStatus) {
         WebTarget resourcePath = tckSuiteTarget.path(TCK_CONTEXT_RESOURCE_PATH).path(where);
         Invocation.Builder builder = resourcePath.request()
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckParticipantTests.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckParticipantTests.java
index cb509c4..68a7156 100644
--- a/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckParticipantTests.java
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckParticipantTests.java
@@ -21,15 +21,20 @@ package org.eclipse.microprofile.lra.tck;
 
 import org.eclipse.microprofile.lra.tck.participant.nonjaxrs.valid.ValidLRACSParticipant;
 import org.eclipse.microprofile.lra.tck.participant.nonjaxrs.valid.ValidLRAParticipant;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricService;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricType;
 import org.jboss.arquillian.container.test.api.Deployment;
 import org.jboss.arquillian.junit.Arquillian;
 import org.jboss.shrinkwrap.api.spec.WebArchive;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import javax.inject.Inject;
+import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Response;
 
+import java.net.URI;
+
 import static org.junit.Assert.assertEquals;
 
 /**
@@ -40,27 +45,15 @@ public class TckParticipantTests extends TckTestBase {
     
     private static final String VALID_DEPLOYMENT = "valid-deploy";
 
-    private int beforeCompletedCount;
-    private int beforeCompensatedCount;
-    private int beforeStatusCount;
-    private int beforeForgetCount;
-    
+    @Inject
+    private LRAMetricService lraMetricService;
+
     @Deployment(name = VALID_DEPLOYMENT)
     public static WebArchive deployValidParticipant() {
         return TckTestBase.deploy(VALID_DEPLOYMENT)
             .addPackage(ValidLRAParticipant.class.getPackage());
     }
     
-    @Before
-    public void before() {
-        super.before();
-
-        beforeCompensatedCount = getCompensateCount();
-        beforeCompletedCount = getCompleteCount();
-        beforeStatusCount = getStatusCount();
-        beforeForgetCount = getForgetCount();
-    }
-
     /**
      * Test verifies that non-JAX-RS @Complete method is invoked according to the 
      * LRA protocol and that if {@link javax.ws.rs.WebApplicationException} is 
@@ -69,17 +62,16 @@ public class TckParticipantTests extends TckTestBase {
      */
     @Test
     public void validWebApplicationExceptionReturnedTest() {
-        Response response = tckSuiteTarget.path(ValidLRAParticipant.RESOURCE_PATH)
-            .path(ValidLRAParticipant.ENLIST_WITH_COMPLETE)
-            .request()
-            .get();
+        WebTarget resourcePath = tckSuiteTarget.path(ValidLRAParticipant.RESOURCE_PATH)
+            .path(ValidLRAParticipant.ENLIST_WITH_COMPLETE);
+        
+        Response response = resourcePath.request().get();
+        URI lraId = URI.create(checkStatusReadAndCloseResponse(Response.Status.OK, response, resourcePath));
 
-        assertEquals("The 200 status response is expected", 
-            Response.Status.OK.getStatusCode(), response.getStatus());
         assertEquals("Non JAX-RS @Complete method throwing WebApplicationException shoud have been called", 
-            beforeCompletedCount + 1, getCompleteCount());
+            1, lraMetricService.getMetric(LRAMetricType.COMPLETE, lraId));
         assertEquals("@Compensate method should not have been called as LRA completed succesfully",
-            beforeCompensatedCount, getCompensateCount());
+            0, lraMetricService.getMetric(LRAMetricType.COMPENSATE, lraId));
 
     }
 
@@ -95,24 +87,24 @@ public class TckParticipantTests extends TckTestBase {
      */
     @Test
     public void validSignaturesChainTest() throws InterruptedException {
-        Response response = tckSuiteTarget.path(ValidLRAParticipant.RESOURCE_PATH)
-            .path(ValidLRAParticipant.ENLIST_WITH_COMPENSATE)
-            .request()
-            .get();
+        WebTarget resourcePath = tckSuiteTarget.path(ValidLRAParticipant.RESOURCE_PATH)
+            .path(ValidLRAParticipant.ENLIST_WITH_COMPENSATE);
+        
+        Response response = resourcePath.request().get();
 
-        assertEquals("The 500 status response is expected", 
-            Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());
+        URI lraId = URI.create(checkStatusReadAndCloseResponse(Response.Status.INTERNAL_SERVER_ERROR, response, resourcePath));
+        
         assertEquals("Non JAX-RS @Compensate method should have been called",
-            beforeCompensatedCount + 1, getCompensateCount());
+            1, lraMetricService.getMetric(LRAMetricType.COMPENSATE, lraId));
         assertEquals("@Complete method should not have been called as LRA compensated",
-            beforeCompletedCount, getCompleteCount());
-        
+            0, lraMetricService.getMetric(LRAMetricType.COMPLETE, lraId));
+
         replayEndPhase(ValidLRAParticipant.RESOURCE_PATH);
-        
+
         assertEquals("Non JAX-RS @Status method should have been called", 
-            beforeStatusCount + 1, getStatusCount());
+            1, lraMetricService.getMetric(LRAMetricType.STATUS, lraId));
         assertEquals("Non JAX-RS @Forget method should have been called",
-            beforeForgetCount + 1, getForgetCount());
+            1, lraMetricService.getMetric(LRAMetricType.FORGET, lraId));
 
     }
 
@@ -122,20 +114,17 @@ public class TckParticipantTests extends TckTestBase {
      */
     @Test
     public void testNonJaxRsCompletionStageVoid() {
-        int beforeCompletedCount = getCompleteCount(ValidLRACSParticipant.ROOT_PATH);
-        int beforeCompensateCount = getCompensateCount(ValidLRACSParticipant.ROOT_PATH);
-        
-        Response response = tckSuiteTarget.path(ValidLRACSParticipant.ROOT_PATH)
-            .path(ValidLRACSParticipant.ENLIST_WITH_COMPENSATE)
-            .request()
-            .get();
+        WebTarget resourcePath = tckSuiteTarget.path(ValidLRACSParticipant.ROOT_PATH)
+            .path(ValidLRACSParticipant.ENLIST_WITH_COMPENSATE);
+
+        Response response = resourcePath.request().get();
+
+        URI lraId = URI.create(checkStatusReadAndCloseResponse(Response.Status.INTERNAL_SERVER_ERROR, response, resourcePath));
 
-        assertEquals("The 500 status response is expected",
-            Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());
         assertEquals("Non JAX-RS @Compensate method with CompletionStage<Void> should have been called",
-            beforeCompensateCount + 1, getCompensateCount(ValidLRACSParticipant.ROOT_PATH));
+            1, lraMetricService.getMetric(LRAMetricType.COMPENSATE, lraId));
         assertEquals("Non JAX-RS @Complete method should have not been called",
-            beforeCompletedCount, getCompleteCount(ValidLRACSParticipant.ROOT_PATH));
+            0, lraMetricService.getMetric(LRAMetricType.COMPLETE, lraId));
     }
 
     /**
@@ -145,61 +134,21 @@ public class TckParticipantTests extends TckTestBase {
      */
     @Test
     public void testNonJaxRsCompletionStageResponseAndParticipantStatus() throws InterruptedException {
-        int beforeCompletedCount = getCompleteCount(ValidLRACSParticipant.ROOT_PATH);
-        int beforeCompensateCount = getCompensateCount(ValidLRACSParticipant.ROOT_PATH);
-        int beforeStatusCount = getStatusCount(ValidLRACSParticipant.ROOT_PATH);
+        WebTarget resourcePath = tckSuiteTarget.path(ValidLRACSParticipant.ROOT_PATH)
+            .path(ValidLRACSParticipant.ENLIST_WITH_COMPLETE);
 
-        Response response = tckSuiteTarget.path(ValidLRACSParticipant.ROOT_PATH)
-            .path(ValidLRACSParticipant.ENLIST_WITH_COMPLETE)
-            .request()
-            .get();
+        Response response = resourcePath.request().get();
+
+        URI lraId = URI.create(checkStatusReadAndCloseResponse(Response.Status.OK, response, resourcePath));
 
-        assertEquals("The 200 status response is expected",
-            Response.Status.OK.getStatusCode(), response.getStatus());
         assertEquals("Non JAX-RS @Complete method with CompletionStage<Response> should have been called",
-            beforeCompletedCount + 1, getCompleteCount(ValidLRACSParticipant.ROOT_PATH));
+            1, lraMetricService.getMetric(LRAMetricType.COMPLETE, lraId));
         assertEquals("Non JAX-RS @Compensate method should have not been called",
-            beforeCompensateCount, getCompensateCount(ValidLRACSParticipant.ROOT_PATH));
-        
-        replayEndPhase(ValidLRACSParticipant.ROOT_PATH);
-        
-        assertEquals("Non JAX-RS @Status method with CompletionStage<ParticipantStatus> should have been called",
-            beforeStatusCount + 1, getStatusCount(ValidLRACSParticipant.ROOT_PATH));
-    }
+            0, lraMetricService.getMetric(LRAMetricType.COMPENSATE, lraId));
 
-    private int getCompleteCount() {
-        return getCompleteCount(ValidLRAParticipant.RESOURCE_PATH);
-    }
-
-    private int getCompensateCount() {
-        return getCompensateCount(ValidLRAParticipant.RESOURCE_PATH);
-    }
-
-    private int getStatusCount() {
-        return getStatusCount(ValidLRAParticipant.RESOURCE_PATH);
-    }
-
-    private int getForgetCount() {
-        Response response = tckSuiteTarget.path(ValidLRAParticipant.RESOURCE_PATH)
-            .path(ValidLRAParticipant.FORGET_COUNT_PATH).request().get();
-        return response.readEntity(Integer.class);
-    }
-
-    private int getCompleteCount(String path) {
-        Response response = tckSuiteTarget.path(path)
-            .path(ValidLRAParticipant.COMPLETED_COUNT_PATH).request().get();
-        return response.readEntity(Integer.class);
-    }
-
-    private int getCompensateCount(String path) {
-        Response response = tckSuiteTarget.path(path)
-            .path(ValidLRAParticipant.COMPENSATED_COUNT_PATH).request().get();
-        return response.readEntity(Integer.class);
-    }
+        replayEndPhase(ValidLRACSParticipant.ROOT_PATH);
 
-    private int getStatusCount(String path) {
-        Response response = tckSuiteTarget.path(path)
-            .path(ValidLRAParticipant.STATUS_COUNT_PATH).request().get();
-        return response.readEntity(Integer.class);
+        assertEquals("Non JAX-RS @Status method with CompletionStage<ParticipantStatus> should have been called",
+            1, lraMetricService.getMetric(LRAMetricType.STATUS, lraId));
     }
 }
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckTestBase.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckTestBase.java
index 00c061b..8d5f78c 100644
--- a/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckTestBase.java
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckTestBase.java
@@ -23,6 +23,7 @@ import org.eclipse.microprofile.lra.annotation.ws.rs.LRA;
 import org.eclipse.microprofile.lra.tck.participant.activity.Activity;
 import org.eclipse.microprofile.lra.tck.participant.api.LraController;
 import org.eclipse.microprofile.lra.tck.participant.api.Util;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricService;
 import org.jboss.shrinkwrap.api.ShrinkWrap;
 import org.jboss.shrinkwrap.api.asset.EmptyAsset;
 import org.jboss.shrinkwrap.api.spec.WebArchive;
@@ -57,6 +58,9 @@ public class TckTestBase {
     @Inject
     private LraTckConfigBean config;
 
+    @Inject
+    private LRAMetricService lraMetricService;    
+
     LRAClientOps lraClient;
 
     private static Client tckSuiteClient;
@@ -68,7 +72,8 @@ public class TckTestBase {
             .create(WebArchive.class, archiveName + ".war")
             .addPackages(false, TckTestBase.class.getPackage(),
                 Activity.class.getPackage(),
-                LraController.class.getPackage())
+                LraController.class.getPackage(),
+                LRAMetricService.class.getPackage())
             .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
     }
     
@@ -82,7 +87,9 @@ public class TckTestBase {
     @Before
     public void before() {
         LOGGER.info("Running test: " + testName.getMethodName());
-        setUpTestCase();
+        
+        tckSuiteClient = ClientBuilder.newClient();
+        lraMetricService.clear();
 
         try {
             tckSuiteTarget = tckSuiteClient.target(URI.create(new URL(config.tckSuiteBaseUrl()).toExternalForm()));
@@ -92,13 +99,6 @@ public class TckTestBase {
         }
     }
 
-    /**
-     * Checking if coordinator is running, set ups the client to contact the recovery manager and the TCK suite itself.
-     */
-    private void setUpTestCase() {
-        tckSuiteClient = ClientBuilder.newClient();
-    }
-
     void checkStatusAndCloseResponse(Response.Status expectedStatus, Response response, WebTarget resourcePath) {
         try {
             assertEquals("Not expected status at call '" + resourcePath.getUri() + "'",
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckTests.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckTests.java
index 3653ba0..d327090 100644
--- a/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckTests.java
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckTests.java
@@ -23,8 +23,6 @@ import static org.eclipse.microprofile.lra.annotation.ws.rs.LRA.LRA_HTTP_CONTEXT
 import static org.eclipse.microprofile.lra.tck.participant.api.LraController.ACCEPT_WORK;
 import static org.eclipse.microprofile.lra.tck.participant.api.LraController.LRA_CONTROLLER_PATH;
 import static org.eclipse.microprofile.lra.tck.participant.api.LraController.TRANSACTIONAL_WORK_PATH;
-import static org.eclipse.microprofile.lra.tck.participant.api.ParticipatingTckResource.COMPENSATED_CNT_PATH;
-import static org.eclipse.microprofile.lra.tck.participant.api.ParticipatingTckResource.COMPLETED_CNT_PATH;
 import static org.eclipse.microprofile.lra.tck.participant.api.ParticipatingTckResource.JOIN_WITH_EXISTING_LRA_PATH;
 import static org.eclipse.microprofile.lra.tck.participant.api.ParticipatingTckResource.JOIN_WITH_EXISTING_LRA_PATH2;
 import static org.eclipse.microprofile.lra.tck.participant.api.ParticipatingTckResource.TCK_PARTICIPANT_RESOURCE_PATH;
@@ -40,13 +38,18 @@ import java.net.URISyntaxException;
 import java.time.temporal.ChronoUnit;
 import java.util.stream.IntStream;
 
+import javax.inject.Inject;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Response;
 
 import org.eclipse.microprofile.lra.tck.participant.api.GenericLRAException;
+import org.eclipse.microprofile.lra.tck.participant.api.LraController;
 import org.eclipse.microprofile.lra.tck.participant.api.NoLRAController;
+import org.eclipse.microprofile.lra.tck.participant.api.ParticipatingTckResource;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricService;
+import org.eclipse.microprofile.lra.tck.service.LRAMetricType;
 import org.jboss.arquillian.container.test.api.Deployment;
 import org.jboss.arquillian.junit.Arquillian;
 import org.jboss.shrinkwrap.api.spec.WebArchive;
@@ -56,6 +59,10 @@ import org.junit.runner.RunWith;
 
 @RunWith(Arquillian.class)
 public class TckTests extends TckTestBase {
+
+    @Inject
+    private LRAMetricService lraMetricService;
+    
     private enum CompletionType {
         complete, compensate, mixed
     }
@@ -163,8 +170,6 @@ public class TckTests extends TckTestBase {
 
     @Test
     public void joinLRAViaHeader() throws WebApplicationException {
-        int beforeCompletedCount = getCompletedCount(false);
-
         URI lra = lraClient.startLRA(null, lraClientId(), lraTimeout(), ChronoUnit.MILLIS);
 
         WebTarget resourcePath = tckSuiteTarget.path(LRA_CONTROLLER_PATH).path(TRANSACTIONAL_WORK_PATH);
@@ -179,13 +184,14 @@ public class TckTests extends TckTestBase {
 
         // close the LRA
         lraClient.closeLRA(lra);
-
+        applyConsistencyDelay();
+        
         // check that participant was told to complete
-        int completedCount = getCompletedCount(true);
         assertEquals("Wrong completion count for call " + resourcePath.getUri() + ". Expecting the method LRA was completed "
-                + "after joining the existing LRA " + lra, beforeCompletedCount + 1, completedCount);
+                + "after joining the existing LRA " + lra, 
+                1, lraMetricService.getMetric(LRAMetricType.COMPLETE, lra, LraController.class.getName()));
+        
         // check that LRA coordinator no longer knows about lraId
-
         assertTrue("LRA '" + lra + "' should not be active anymore as it was closed yet.",
                 lraClient.isLRAFinished(lra));
     }
@@ -204,7 +210,6 @@ public class TckTests extends TckTestBase {
 
     @Test
     public void leaveLRA() throws WebApplicationException {
-        int beforeCompletedCount = getCompletedCount(false);
         URI lra = lraClient.startLRA(null, lraClientId(), lraTimeout(), ChronoUnit.MILLIS);
         WebTarget resourcePath = tckSuiteTarget.path(LRA_CONTROLLER_PATH).path(TRANSACTIONAL_WORK_PATH);
         Response response = resourcePath.request().header(LRA_HTTP_CONTEXT_HEADER, lra).put(Entity.text(""));
@@ -222,13 +227,13 @@ public class TckTests extends TckTestBase {
         checkStatusAndCloseResponse(Response.Status.OK, response, resourcePath);
 
         lraClient.closeLRA(lra);
+        applyConsistencyDelay();
 
         // check that participant was not told to complete
-        int completedCount = getCompletedCount(true);
-
         assertEquals("Wrong completion count when participant left the LRA. "
                 + "Expecting the completed count hasn't change between start and end of the test. "
-                + "The test call went to LRA controller at " + resourcePath.getUri(), beforeCompletedCount, completedCount);
+                + "The test call went to LRA controller at " + resourcePath.getUri(), 
+                -1, lraMetricService.getMetric(LRAMetricType.COMPLETE, lra, LraController.class.getName()));
     }
 
     @Test
@@ -252,14 +257,12 @@ public class TckTests extends TckTestBase {
 
     @Test
     public void timeLimit() {
-        int beforeCompletedCount = getCompletedCount(false);
-        int beforeCompensatedCount = getCompensatedCount(false);
-        
         WebTarget resourcePath = tckSuiteTarget.path(LRA_CONTROLLER_PATH).path("timeLimit");
         Response response = resourcePath
                 .request()
                 .get();
 
+        URI lraId = URI.create(response.readEntity(String.class));
         response.close();
 
         // Note that the timeout firing will cause the coordinator to compensate
@@ -267,9 +270,8 @@ public class TckTests extends TckTestBase {
         // (depends upon how long the coordinator keeps a record of finished LRAs
 
         // check that participant was invoked
-        int completedCount = getCompletedCount(true);
-        int compensatedCount = getCompensatedCount(false);
-
+        applyConsistencyDelay();
+        
         /*
          * The call to activities/timeLimit should have started an LRA which should have timed out
          * (because the invoked resource method sleeps for longer than the timeLimit annotation
@@ -277,10 +279,12 @@ public class TckTests extends TckTestBase {
          */
         assertEquals("The LRA should have timed out but complete was called instead of compensate. "
                 + "Expecting the number of complete call before test matches the ones after LRA timed out. "
-                + "The test call went to " + resourcePath.getUri(), beforeCompletedCount, completedCount);
+                + "The test call went to " + resourcePath.getUri(), 
+                0, lraMetricService.getMetric(LRAMetricType.COMPLETE, lraId, LraController.class.getName()));
         assertEquals("The LRA should have timed out and compensate should be called. "
                 + "Expecting the number of compensate call before test is one less lower than the ones after LRA timed out. "
-                + "The test call went to " + resourcePath.getUri(), beforeCompensatedCount + 1, compensatedCount);
+                + "The test call went to " + resourcePath.getUri(), 
+                1, lraMetricService.getMetric(LRAMetricType.COMPENSATE, lraId, LraController.class.getName()));
     }
 
     @Test
@@ -296,8 +300,6 @@ public class TckTests extends TckTestBase {
     private void joinAndEnd(boolean close, String path, String path2)
             throws WebApplicationException, InterruptedException {
         URI lra = lraClient.startLRA(null, lraClientId(), lraTimeout(), ChronoUnit.MILLIS);
-        int beforeCompletionCount = getCompletedCount(false);
-        int beforeCompensationCount = getCompensatedCount(false);
         WebTarget resourcePath = tckSuiteTarget.path(path).path(path2);
 
         Response response = resourcePath
@@ -312,9 +314,10 @@ public class TckTests extends TckTestBase {
         }
 
         replayEndPhase(null);
+        applyConsistencyDelay();
 
-        int completionCount = getCompletedCount(false) - beforeCompletionCount;
-        int compensationCount = getCompensatedCount(true) - beforeCompensationCount;
+        int completionCount = lraMetricService.getMetric(LRAMetricType.COMPLETE, lra, LraController.class.getName());
+        int compensationCount = lraMetricService.getMetric(LRAMetricType.COMPENSATE, lra, LraController.class.getName());
 
         boolean wasCalled = (close ? completionCount > 0 : compensationCount > 0);
         boolean wasNotCalled = (close ? compensationCount == 0 : completionCount == 0);
@@ -336,8 +339,6 @@ public class TckTests extends TckTestBase {
                 .path(NoLRAController.NO_LRA_CONTROLLER_PATH)
                 .path(NoLRAController.NON_TRANSACTIONAL_WORK_PATH);
 
-        int beforeCompletedCount = getCompletedCount(false);
-        int beforeCompensatedCount = getCompensatedCount(false);
         URI lra = lraClient.startLRA(null, lraClientId(), lraTimeout(), ChronoUnit.MILLIS);
 
         Response response = resourcePath.request().header(LRA_HTTP_CONTEXT_HEADER, lra)
@@ -349,18 +350,19 @@ public class TckTests extends TckTestBase {
                 lraId, lra.toString());
 
         lraClient.cancelLRA(lra);
+        applyConsistencyDelay();
 
         // check that second service (the LRA aware one), namely
-        // {@link org.eclipse.microprofile.lra.tck.participant.api.ActivityController#activityWithMandatoryLRA(String, String)}
+        // {@link org.eclipse.microprofile.lra.tck.participant.api.LraController#activityWithMandatoryLRA(String, String)}
         // was told to compensate
-        int completedCount = getCompletedCount(true);
-        int compensatedCount = getCompensatedCount(false);
+        int completedCount = lraMetricService.getMetric(LRAMetricType.COMPLETE, lra, LraController.class.getName());
+        int compensatedCount = lraMetricService.getMetric(LRAMetricType.COMPENSATE, lra, LraController.class.getName());
 
         assertEquals("Complete should not be called on the LRA aware service. "
                 + "The number of completed count for before and after test does not match. "
-                + "The test call went to " + resourcePath.getUri(), beforeCompletedCount, completedCount);
+                + "The test call went to " + resourcePath.getUri(), 0, completedCount);
         assertEquals("Compensate service should be called on LRA aware service. The number of compensated count after test is bigger for one. "
-                + "The test call went to " + resourcePath.getUri(), beforeCompensatedCount + 1, compensatedCount);
+                + "The test call went to " + resourcePath.getUri(), 1, compensatedCount);
     }
 
     /**
@@ -429,10 +431,6 @@ public class TckTests extends TckTestBase {
 
     private void joinWithOneResource(String methodName, boolean close, String resource1Method, String resource2Method)
             throws WebApplicationException {
-        // get the initial values for the number of completions and compensations
-        int completedCount = getActivityCount(false, TCK_PARTICIPANT_RESOURCE_PATH, COMPLETED_CNT_PATH);
-        int compensatedCount = getActivityCount(false, TCK_PARTICIPANT_RESOURCE_PATH, COMPENSATED_CNT_PATH);
-
         // set up the web target for the test
         WebTarget resource1Path = tckSuiteTarget.path(TCK_PARTICIPANT_RESOURCE_PATH).path(resource1Method);
         WebTarget resource2Path = tckSuiteTarget.path(TCK_PARTICIPANT_RESOURCE_PATH).path(resource2Method);
@@ -447,26 +445,22 @@ public class TckTests extends TckTestBase {
 
         if (close) {
             lraClient.closeLRA(lra);
-
+            applyConsistencyDelay();
+            
             assertTrue(methodName + ": resource should have completed once with no compensations",
-                    completedCount + 1 == getActivityCount(true, TCK_PARTICIPANT_RESOURCE_PATH, COMPLETED_CNT_PATH)
-                            && compensatedCount == getActivityCount(true, TCK_PARTICIPANT_RESOURCE_PATH, COMPENSATED_CNT_PATH));
+                    1 == lraMetricService.getMetric(LRAMetricType.COMPLETE, lra, ParticipatingTckResource.class.getName()) && 
+                    0 == lraMetricService.getMetric(LRAMetricType.COMPENSATE, lra, ParticipatingTckResource.class.getName()));
         } else {
             lraClient.cancelLRA(lra);
+            applyConsistencyDelay();
 
             assertTrue(methodName + ":: resource should have compensated once with no completions",
-                    completedCount == getActivityCount(true, TCK_PARTICIPANT_RESOURCE_PATH, COMPLETED_CNT_PATH)
-                            && compensatedCount + 1 == getActivityCount(false, TCK_PARTICIPANT_RESOURCE_PATH, COMPENSATED_CNT_PATH));
+                    0 == lraMetricService.getMetric(LRAMetricType.COMPLETE, lra, ParticipatingTckResource.class.getName()) &&
+                    1 == lraMetricService.getMetric(LRAMetricType.COMPENSATE, lra, ParticipatingTckResource.class.getName()));
         }
     }
 
     private void joinWithTwoResources(boolean close) throws WebApplicationException {
-        // get the initial values for the number of completions and compensations
-        int completedCount1 = getActivityCount(false, LRA_CONTROLLER_PATH, "completedactivitycount");
-        int compensatedCount1 = getActivityCount(false, LRA_CONTROLLER_PATH, "compensatedactivitycount");
-        int completedCount2 = getActivityCount(false, TCK_PARTICIPANT_RESOURCE_PATH, COMPLETED_CNT_PATH);
-        int compensatedCount2 = getActivityCount(false, TCK_PARTICIPANT_RESOURCE_PATH, COMPENSATED_CNT_PATH);
-
         // set up the web target for the test
         WebTarget resource1Path = tckSuiteTarget.path(LRA_CONTROLLER_PATH).path(TRANSACTIONAL_WORK_PATH);
         WebTarget resource2Path = tckSuiteTarget.path(TCK_PARTICIPANT_RESOURCE_PATH).path(JOIN_WITH_EXISTING_LRA_PATH);
@@ -481,49 +475,24 @@ public class TckTests extends TckTestBase {
 
         if (close) {
             lraClient.closeLRA(lra);
+            applyConsistencyDelay();
 
             assertTrue("joinWithTwoResourcesWithClose: both resources should have completed",
-                    getActivityCount(true, LRA_CONTROLLER_PATH, "completedactivitycount") == completedCount1 + 1
-                            && getActivityCount(false, TCK_PARTICIPANT_RESOURCE_PATH, COMPLETED_CNT_PATH) == completedCount2 + 1);
+                    lraMetricService.getMetric(LRAMetricType.COMPLETE, lra, LraController.class.getName()) == 1 &&
+                    lraMetricService.getMetric(LRAMetricType.COMPLETE, lra, ParticipatingTckResource.class.getName()) == 1);
         } else {
             lraClient.cancelLRA(lra);
+            applyConsistencyDelay();
 
             assertTrue("joinWithTwoResourcesWithCancel: both resources should have compensated",
-                    getActivityCount(true, LRA_CONTROLLER_PATH, "compensatedactivitycount") == compensatedCount1 +1
-                            && getActivityCount(false, TCK_PARTICIPANT_RESOURCE_PATH, COMPENSATED_CNT_PATH) == compensatedCount2 + 1);
+                    lraMetricService.getMetric(LRAMetricType.COMPENSATE, lra, LraController.class.getName()) == 1 &&
+                    lraMetricService.getMetric(LRAMetricType.COMPENSATE, lra, ParticipatingTckResource.class.getName()) == 1);
         }
     }
 
-    private int getCompletedCount(boolean delay) {
-        return getActivityCount(delay, "completedactivitycount");
-    }
-
-    private int getCompensatedCount(boolean delay) {
-        return getActivityCount(delay, "compensatedactivitycount");
-    }
-
-    private int getActivityCount(boolean delay, String activityCountTargetPath) {
-        return getActivityCount(delay, LRA_CONTROLLER_PATH, activityCountTargetPath);
-    }
-
-    private int getActivityCount(boolean delay, String basePath, String activityCountTargetPath) {
-        if (delay) {
-            applyConsistencyDelay();
-        }
-        WebTarget resourcePath = tckSuiteTarget.path(basePath)
-                .path(activityCountTargetPath);
-
-        Response response = resourcePath.request().get();
-        String count = checkStatusReadAndCloseResponse(Response.Status.OK, response, resourcePath);
-        return Integer.parseInt(count);
-    }
-
     private void multiLevelNestedActivity(CompletionType how, int nestedCnt) throws WebApplicationException {
         WebTarget resourcePath = tckSuiteTarget.path(LRA_CONTROLLER_PATH).path("multiLevelNestedActivity");
 
-        int beforeCompletedCount = getCompletedCount(false);
-        int beforeCompensatedCount = getCompensatedCount(false);
-
         if (how == CompletionType.mixed && nestedCnt <= 1) {
             how = CompletionType.complete;
         }
@@ -561,15 +530,16 @@ public class TckTests extends TckTestBase {
         assertFalse("multiLevelNestedActivity: top level LRA should be active (path called " + resourcePath.getUri() + ")",
                 lraClient.isLRAFinished(lraArray[0]));
 
-        int inMiddleCompletedCount = getCompletedCount(true);
-        int inMiddleCompensatedCount = getCompensatedCount(false);
+        applyConsistencyDelay();
+        int inMiddleCompletedCount = lraMetricService.getMetric(LRAMetricType.COMPLETE);
+        int inMiddleCompensatedCount = lraMetricService.getMetric(LRAMetricType.COMPENSATE);
 
         // check that all nested activities were told to complete
         assertEquals("multiLevelNestedActivity: step 3 (called test path " + resourcePath.getUri() + ")",
-                beforeCompletedCount + nestedCnt, inMiddleCompletedCount);
+                nestedCnt, inMiddleCompletedCount);
         // and that neither were told to compensate
         assertEquals("multiLevelNestedActivity: step 4 (called test path " + resourcePath.getUri() + ")",
-                beforeCompensatedCount, inMiddleCompensatedCount);
+                0, inMiddleCompensatedCount);
 
         // close the LRA
         if (how == CompletionType.compensate) {
@@ -601,8 +571,9 @@ public class TckTests extends TckTestBase {
                         (i == 0 ? "top level" : "nested"), resourcePath.getUri()),
                 lraClient.isLRAFinished(lraArray[i])));
 
-        int afterCompletedCount = getCompletedCount(true);
-        int afterCompensatedCount = getCompensatedCount(false);
+        applyConsistencyDelay();
+        int afterCompletedCount = lraMetricService.getMetric(LRAMetricType.COMPLETE);
+        int afterCompensatedCount = lraMetricService.getMetric(LRAMetricType.COMPENSATE);
 
         if (how == CompletionType.complete) {
             // make sure that all nested activities were not told to complete or cancel a second time
@@ -610,7 +581,7 @@ public class TckTests extends TckTestBase {
                     inMiddleCompletedCount + nestedCnt, afterCompletedCount);
             // and that neither were still not told to compensate
             assertEquals("multiLevelNestedActivity: step 6 (called test path " + resourcePath.getUri() + ")",
-                    beforeCompensatedCount, afterCompensatedCount);
+                    0, afterCompensatedCount);
 
         } else if (how == CompletionType.compensate) {
             /*
@@ -622,7 +593,7 @@ public class TckTests extends TckTestBase {
              */
             // each nested participant should have completed (the +nestedCnt)
             assertEquals("multiLevelNestedActivity: step 7 (called test path " + resourcePath.getUri() + ")",
-                    beforeCompletedCount + nestedCnt, afterCompletedCount);
+                    nestedCnt, afterCompletedCount);
             // each nested participant should have compensated. The top level enlistment should have compensated (the +1)
             assertEquals("multiLevelNestedActivity: step 8 (called test path " + resourcePath.getUri() + ")",
                     inMiddleCompensatedCount + 1 + nestedCnt, afterCompensatedCount);
@@ -634,14 +605,14 @@ public class TckTests extends TckTestBase {
              */
             // there should be just 1 compensation (the first nested LRA)
             assertEquals("multiLevelNestedActivity: step 9 (called test path " + resourcePath.getUri() + ")",
-                    1, afterCompensatedCount - beforeCompensatedCount);
+                    1, afterCompensatedCount);
             /*
              * Expect nestedCnt + 1 completions, 1 for the top level and one for each nested LRA
              * (NB the first nested LRA is completed and compensated)
              * Note that the top level complete should not call complete again on the nested LRA
              */
             assertEquals("multiLevelNestedActivity: step 10 (called test path " + resourcePath.getUri() + ")",
-                    nestedCnt + 1, afterCompletedCount - beforeCompletedCount);
+                    nestedCnt + 1, afterCompletedCount);
         }
     }
 }