diff --git a/build.gradle b/build.gradle index c7480cb46..8bc1ff06e 100644 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,7 @@ targetCompatibility = 1.8 ext { slf4jVersion = '1.7.30' groovyVersion = '3.0.4' + openTracingVersion = '0.33.0' } repositories { @@ -57,7 +58,8 @@ dependencies { 'org.apache.commons:commons-lang3:3.10', 'org.apache.commons:commons-collections4:4.4', 'org.threeten:threeten-extra:1.5.0', - 'org.jooq:jool-java-8:0.9.14' + 'org.jooq:jool-java-8:0.9.14', + "io.opentracing:opentracing-util:$openTracingVersion" implementation 'javax.cache:cache-api:1.1.1', optional implementation "org.codehaus.groovy:groovy:$groovyVersion", optional @@ -72,7 +74,8 @@ dependencies { 'junit:junit:4.13', 'org.ccil.cowan.tagsoup:tagsoup:1.2.1', "org.slf4j:slf4j-log4j12:$slf4jVersion", - 'org.cache2k:cache2k-jcache:1.2.4.Final' + 'org.cache2k:cache2k-jcache:1.2.4.Final', + "io.opentracing:opentracing-mock:$openTracingVersion" } jacocoTestReport { diff --git a/src/main/java/net/fortuna/ical4j/agent/AbstractUserAgent.java b/src/main/java/net/fortuna/ical4j/agent/AbstractUserAgent.java index 8e7ace872..4443cc2e8 100644 --- a/src/main/java/net/fortuna/ical4j/agent/AbstractUserAgent.java +++ b/src/main/java/net/fortuna/ical4j/agent/AbstractUserAgent.java @@ -1,5 +1,7 @@ package net.fortuna.ical4j.agent; +import io.opentracing.Tracer; +import io.opentracing.noop.NoopTracerFactory; import net.fortuna.ical4j.model.Calendar; import net.fortuna.ical4j.model.PropertyList; import net.fortuna.ical4j.model.component.CalendarComponent; @@ -15,18 +17,26 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.Optional; /** * Created by fortuna on 19/07/2017. */ public abstract class AbstractUserAgent implements UserAgent { + protected final Tracer tracer; + private final ProdId prodId; private final Map> methodTransformers; public AbstractUserAgent(ProdId prodId, Organizer organizer, UidGenerator uidGenerator) { + this(prodId, organizer, uidGenerator, null); + } + + public AbstractUserAgent(ProdId prodId, Organizer organizer, UidGenerator uidGenerator, Tracer tracer) { this.prodId = prodId; + this.tracer = Optional.ofNullable(tracer).orElse(NoopTracerFactory.create()); methodTransformers = new HashMap<>(); methodTransformers.put(Method.PUBLISH, new PublishTransformer(organizer, uidGenerator,true)); diff --git a/src/main/java/net/fortuna/ical4j/agent/VEventUserAgent.java b/src/main/java/net/fortuna/ical4j/agent/VEventUserAgent.java index aa4398fb9..299fad118 100644 --- a/src/main/java/net/fortuna/ical4j/agent/VEventUserAgent.java +++ b/src/main/java/net/fortuna/ical4j/agent/VEventUserAgent.java @@ -1,5 +1,8 @@ package net.fortuna.ical4j.agent; +import io.opentracing.Scope; +import io.opentracing.Span; +import io.opentracing.Tracer; import net.fortuna.ical4j.model.Calendar; import net.fortuna.ical4j.model.component.VEvent; import net.fortuna.ical4j.model.property.Method; @@ -17,6 +20,11 @@ public VEventUserAgent(ProdId prodId, Organizer organizer, UidGenerator uidGener delegateTransformer = new RequestTransformer(uidGenerator); } + public VEventUserAgent(ProdId prodId, Organizer organizer, UidGenerator uidGenerator, Tracer tracer) { + super(prodId, organizer, uidGenerator, tracer); + delegateTransformer = new RequestTransformer(uidGenerator); + } + /** *
      * 3.2.1.  PUBLISH
@@ -34,9 +42,14 @@ public VEventUserAgent(ProdId prodId, Organizer organizer, UidGenerator uidGener
      */
     @Override
     public Calendar publish(VEvent... component) {
-        Calendar published = wrap(Method.PUBLISH, component);
-        published.validate();
-        return published;
+        Span span = tracer.buildSpan("veventPublish").start();
+        try (Scope scope = tracer.scopeManager().activate(span)) {
+            Calendar published = wrap(Method.PUBLISH, component);
+            published.validate();
+            return published;
+        } finally {
+            span.finish();
+        }
     }
 
     /**
@@ -89,16 +102,26 @@ public Calendar publish(VEvent... component) {
      */
     @Override
     public Calendar request(VEvent... component) {
-        Calendar request = wrap(Method.REQUEST, component);
-        request.validate();
-        return request;
+        Span span = tracer.buildSpan("veventRequest").start();
+        try (Scope scope = tracer.scopeManager().activate(span)) {
+            Calendar request = wrap(Method.REQUEST, component);
+            request.validate();
+            return request;
+        } finally {
+            span.finish();
+        }
     }
 
     @Override
     public Calendar delegate(Calendar request) {
-        Calendar delegated = delegateTransformer.transform(request.copy());
-        delegated.validate();
-        return delegated;
+        Span span = tracer.buildSpan("veventDelegate").start();
+        try (Scope scope = tracer.scopeManager().activate(span)) {
+            Calendar delegated = delegateTransformer.transform(request.copy());
+            delegated.validate();
+            return delegated;
+        } finally {
+            span.finish();
+        }
     }
 
     /**
@@ -144,9 +167,14 @@ public Calendar delegate(Calendar request) {
      */
     @Override
     public Calendar reply(Calendar request) {
-        Calendar reply = transform(Method.REPLY, request.copy());
-        reply.validate();
-        return reply;
+        Span span = tracer.buildSpan("veventReply").start();
+        try (Scope scope = tracer.scopeManager().activate(span)) {
+            Calendar reply = transform(Method.REPLY, request.copy());
+            reply.validate();
+            return reply;
+        } finally {
+            span.finish();
+        }
     }
 
     /**
@@ -172,9 +200,14 @@ public Calendar reply(Calendar request) {
      */
     @Override
     public Calendar add(VEvent component) {
-        Calendar add = wrap(Method.ADD, component);
-        add.validate();
-        return add;
+        Span span = tracer.buildSpan("veventAdd").start();
+        try (Scope scope = tracer.scopeManager().activate(span)) {
+            Calendar add = wrap(Method.ADD, component);
+            add.validate();
+            return add;
+        } finally {
+            span.finish();
+        }
     }
 
     /**
@@ -215,9 +248,14 @@ public Calendar add(VEvent component) {
      */
     @Override
     public Calendar cancel(VEvent... component) {
-        Calendar cancel = wrap(Method.CANCEL, component);
-        cancel.validate();
-        return cancel;
+        Span span = tracer.buildSpan("veventCancel").start();
+        try (Scope scope = tracer.scopeManager().activate(span)) {
+            Calendar cancel = wrap(Method.CANCEL, component);
+            cancel.validate();
+            return cancel;
+        } finally {
+            span.finish();
+        }
     }
 
     /**
@@ -235,10 +273,15 @@ public Calendar cancel(VEvent... component) {
      */
     @Override
     public Calendar refresh(VEvent component) {
-        Calendar refresh = wrap(Method.REFRESH, component.copy());
+        Span span = tracer.buildSpan("veventRefresh").start();
+        try (Scope scope = tracer.scopeManager().activate(span)) {
+            Calendar refresh = wrap(Method.REFRESH, component.copy());
 //        componentTransformers.get(Method.REFRESH).transform(refresh.getComponents().getAll());
-        refresh.validate();
-        return refresh;
+            refresh.validate();
+            return refresh;
+        } finally {
+            span.finish();
+        }
     }
 
     /**
@@ -264,9 +307,14 @@ public Calendar refresh(VEvent component) {
      */
     @Override
     public Calendar counter(Calendar request) {
-        Calendar counter = transform(Method.COUNTER, request.copy());
-        counter.validate();
-        return counter;
+        Span span = tracer.buildSpan("veventCounter").start();
+        try (Scope scope = tracer.scopeManager().activate(span)) {
+            Calendar counter = transform(Method.COUNTER, request.copy());
+            counter.validate();
+            return counter;
+        } finally {
+            span.finish();
+        }
     }
 
     /**
@@ -282,8 +330,13 @@ public Calendar counter(Calendar request) {
      */
     @Override
     public Calendar declineCounter(Calendar counter) {
-        Calendar declineCounter = transform(Method.DECLINE_COUNTER, counter.copy());
-        declineCounter.validate();
-        return declineCounter;
+        Span span = tracer.buildSpan("veventDeclineCounter").start();
+        try (Scope scope = tracer.scopeManager().activate(span)) {
+            Calendar declineCounter = transform(Method.DECLINE_COUNTER, counter.copy());
+            declineCounter.validate();
+            return declineCounter;
+        } finally {
+            span.finish();
+        }
     }
 }
diff --git a/src/test/groovy/net/fortuna/ical4j/agent/VEventUserAgentTest.groovy b/src/test/groovy/net/fortuna/ical4j/agent/VEventUserAgentTest.groovy
index 82b06e6d1..125cc4df7 100644
--- a/src/test/groovy/net/fortuna/ical4j/agent/VEventUserAgentTest.groovy
+++ b/src/test/groovy/net/fortuna/ical4j/agent/VEventUserAgentTest.groovy
@@ -1,5 +1,7 @@
 package net.fortuna.ical4j.agent
 
+
+import io.opentracing.mock.MockTracer
 import net.fortuna.ical4j.model.ContentBuilder
 import net.fortuna.ical4j.model.Property
 import net.fortuna.ical4j.model.property.Method
@@ -12,11 +14,12 @@ import spock.lang.Specification
 
 class VEventUserAgentTest extends Specification {
 
+    MockTracer tracer = []
     ProdId prodId = ['-//Ben Fortuna//iCal4j 2.0//EN']
     UidGenerator uidGenerator = new RandomUidGenerator()
     Organizer org = []
 
-    VEventUserAgent userAgent = [prodId, org, uidGenerator]
+    VEventUserAgent userAgent = [prodId, org, uidGenerator, tracer]
 
     ContentBuilder builder = []
 
@@ -48,6 +51,10 @@ class VEventUserAgentTest extends Specification {
 
         and: 'the sequence property is present on all components'
         calendar.components.all.each { it.getProperties().getFirst(Property.SEQUENCE).isPresent() }
+
+        and: 'tracing completed as expected'
+        tracer.finishedSpans().size() == 1
+        tracer.finishedSpans()[0].operationName() == 'veventPublish'
     }
 
     def "Request"() {
@@ -82,6 +89,10 @@ class VEventUserAgentTest extends Specification {
 
         and: 'the sequence property is present on all components'
         calendar.components.all.each { it.getProperties().getFirst(Property.SEQUENCE).isPresent() }
+
+        and: 'tracing completed as expected'
+        tracer.finishedSpans().size() == 1
+        tracer.finishedSpans()[0].operationName() == 'veventRequest'
     }
 
     def "Delegate"() {
@@ -106,6 +117,10 @@ class VEventUserAgentTest extends Specification {
 
         then: 'the calendar object contains method = REQUEST'
         calendar.getProperties().getRequired(Property.METHOD) == Method.REQUEST
+
+        and: 'tracing completed as expected'
+        tracer.finishedSpans().size() == 1
+        tracer.finishedSpans()[0].operationName() == 'veventDelegate'
     }
 
     def "Reply"() {
@@ -130,6 +145,10 @@ class VEventUserAgentTest extends Specification {
 
         then: 'the calendar object contains method = REPLY'
         calendar.getProperties().getRequired(Property.METHOD) == Method.REPLY
+
+        and: 'tracing completed as expected'
+        tracer.finishedSpans().size() == 1
+        tracer.finishedSpans()[0].operationName() == 'veventReply'
     }
 
     def "Add"() {
@@ -148,6 +167,10 @@ class VEventUserAgentTest extends Specification {
 
         then: 'the calendar object contains method = ADD'
         calendar.getProperties().getRequired(Property.METHOD) == Method.ADD
+
+        and: 'tracing completed as expected'
+        tracer.finishedSpans().size() == 1
+        tracer.finishedSpans()[0].operationName() == 'veventAdd'
     }
 
     def "Cancel"() {
@@ -165,6 +188,10 @@ class VEventUserAgentTest extends Specification {
 
         then: 'the calendar object contains method = CANCEL'
         calendar.getProperties().getRequired(Property.METHOD) == Method.CANCEL
+
+        and: 'tracing completed as expected'
+        tracer.finishedSpans().size() == 1
+        tracer.finishedSpans()[0].operationName() == 'veventCancel'
     }
 
     def "Refresh"() {
@@ -183,6 +210,10 @@ class VEventUserAgentTest extends Specification {
 
         then: 'the calendar object contains method = REFRESH'
         calendar.getProperties().getRequired(Property.METHOD) == Method.REFRESH
+
+        and: 'tracing completed as expected'
+        tracer.finishedSpans().size() == 1
+        tracer.finishedSpans()[0].operationName() == 'veventRefresh'
     }
 
     def "Counter"() {
@@ -207,6 +238,10 @@ class VEventUserAgentTest extends Specification {
 
         then: 'the calendar object contains method = COUNTER'
         calendar.getProperties().getRequired(Property.METHOD) == Method.COUNTER
+
+        and: 'tracing completed as expected'
+        tracer.finishedSpans().size() == 1
+        tracer.finishedSpans()[0].operationName() == 'veventCounter'
     }
 
     def "DeclineCounter"() {
@@ -228,5 +263,9 @@ class VEventUserAgentTest extends Specification {
 
         then: 'the calendar object contains method = DECLINECOUNTER'
         calendar.getProperties().getRequired(Property.METHOD) == Method.DECLINE_COUNTER
+
+        and: 'tracing completed as expected'
+        tracer.finishedSpans().size() == 1
+        tracer.finishedSpans()[0].operationName() == 'veventDeclineCounter'
     }
 }