ExtraFactory { public final TraceContext decorate(TraceContext context) { long traceId = context.traceId(), spanId = context.spanId(); E claimed = null; int existingIndex = -1, extraLength = context.extra().size(); for (int i = 0; i < extraLength; i++) { Object next = context.extra().get(i); if (next instanceof Extra) { Extra nextExtra = (Extra) next; if (nextExtra.factory != this) continue; if (claimed == null && nextExtra.tryToClaim(traceId, spanId)) { claimed = (E) nextExtra; continue; } if (existingIndex == -1) { existingIndex = i; } else { Platform.get().log("BUG: something added redundant extra instances %s", context, null); return context; } } } if (claimed != null && existingIndex == -1) { return context; } if (claimed == null) { claimed = create(); if (claimed == null) { Platform.get().log("BUG: create() returned null", null); return context; } claimed.tryToClaim(traceId, spanId); } TraceContext.Builder builder = context.toBuilder().clearExtra().addExtra(claimed); for (int i = 0; i < extraLength; i++) { Object next = context.extra().get(i); if (i == existingIndex) { E existing = (E) next; if (claimed.state == initialState) { claimed.state = existing.state; } else if (existing.state != initialState) { claimed.mergeStateKeepingOursOnConflict(existing); } } else if (!next.equals(claimed)) { builder.addExtra(next); } } return builder.build(); } protected  ExtraFactory(Object initialState); final TraceContext decorate(TraceContext context);  }
@Test public void contextsAreIndependent() { TraceContext decorated = propagationFactory.decorate(context); BasicMapExtra extra1 = decorated.findExtra(BasicMapExtra.class); extra1.put("1", "one"); context2 = propagationFactory.decorate(context2.toBuilder().addExtra(extra1).build()); BasicMapExtra extra2 = context2.findExtra(BasicMapExtra.class); assertThat(extra1).isNotSameAs(extra2); assertThat(extra1).isEqualTo(extra2); extra1.put("1", "two"); extra2.put("1", "three"); assertThat(extra1.get("1")).isEqualTo("two"); assertThat(extra2.get("1")).isEqualTo("three"); }
@Test public void contextsHaveIndependentValue() { TraceContext decorated = propagationFactory.decorate(context); BasicMapExtra extra1 = decorated.findExtra(BasicMapExtra.class); extra1.put("1", "two"); assertThat(propagationFactory.decorate(decorated.toBuilder().build()).extra()) .isEqualTo(decorated.extra()); context2 = propagationFactory.decorate(context2.toBuilder().addExtra(extra1).build()); BasicMapExtra extra2 = context2.findExtra(BasicMapExtra.class); assertThat(extra1).isNotSameAs(extra2); assertThat(extra1).isEqualTo(extra2); String beforeUpdate = extra1.get("1"); extra1.put("1", "2"); assertThat(extra1.get("1")).isNotEqualTo(beforeUpdate); assertThat(extra2.get("1")).isEqualTo(beforeUpdate); }
@Test public void decorate_parent() { TraceContext decorated = propagationFactory.decorate(context); BasicMapExtra extra1 = decorated.findExtra(BasicMapExtra.class); extra1.put("1", "one"); context2 = propagationFactory.decorate(context2.toBuilder().addExtra(extra1).build()); BasicMapExtra extra2 = context2.findExtra(BasicMapExtra.class); assertThat(context2.extra()).containsExactly(extra2); assertThat(extra2.get("1")).isEqualTo("one"); assertExtraClaimed(context2); }
@Test public void idempotent() { TraceContext decorated = propagationFactory.decorate(context); List<Object> originalExtra = decorated.extra(); assertThat(propagationFactory.decorate(decorated).extra()) .isSameAs(originalExtra); }
@Test public void decorate_makesNewExtra() { List<TraceContext> contexts = asList( context.toBuilder().build(), context.toBuilder().addExtra(1L).build(), context.toBuilder().addExtra(1L).addExtra(2L).build() ); for (TraceContext context : contexts) { TraceContext ensured = factory.decorate(context); assertThat(ensured.extra()) .hasSize(context.extra().size() + 1) .containsAll(context.extra()); assertExtraClaimed(ensured); } }
@Test public void decorate_forksWhenFieldsAlreadyClaimed() { TraceContext other = TraceContext.newBuilder().traceId(98L).spanId(99L).build(); BasicMapExtra claimed = factory.decorate(other).findExtra(BasicMapExtra.class); List<TraceContext> contexts = asList( context.toBuilder().addExtra(claimed).build(), context.toBuilder().addExtra(1L).addExtra(claimed).build(), context.toBuilder().addExtra(claimed).addExtra(1L).build(), context.toBuilder().addExtra(1L).addExtra(claimed).addExtra(2L).build() ); for (TraceContext context : contexts) { TraceContext ensured = factory.decorate(context); assertThat(ensured).isNotSameAs(context); assertThat(ensured.extra()) .isNotSameAs(context.extra()) .hasSize(context.extra().size()); assertExtraClaimed(ensured); } }
@Test public void decorate_claimsContext() { assertExtraClaimed(propagationFactory.decorate(context)); }