diff --git a/opentracing-specialagent/pom.xml b/opentracing-specialagent/pom.xml
index b06113544..52c24bdc5 100644
--- a/opentracing-specialagent/pom.xml
+++ b/opentracing-specialagent/pom.xml
@@ -470,13 +470,6 @@
true
provided
-
- io.opentracing.contrib.specialagent.rule
- mule-4-http-service
- ${project.version}
- true
- provided
-
io.opentracing.contrib.specialagent.rule
mule-4-module-artifact
diff --git a/rule/grizzly-http-server/pom.xml b/rule/grizzly-http-server/pom.xml
index 0dc98daf8..cd2c1b4b4 100644
--- a/rule/grizzly-http-server/pom.xml
+++ b/rule/grizzly-http-server/pom.xml
@@ -28,7 +28,7 @@
grizzly:http-server
2.3.35
- 0.1.3
+ 0.2.0
@@ -42,15 +42,10 @@
-
- org.glassfish.grizzly
- grizzly-framework
- org.glassfish.grizzly:grizzly-framework:[${min.version},]
-
org.glassfish.grizzly
grizzly-http
- org.glassfish.grizzly:grizzly-framework:[${min.version},]
+ org.glassfish.grizzly:grizzly-http:[${min.version},]
@@ -76,13 +71,6 @@
test-jar
test
-
- org.glassfish.grizzly
- grizzly-framework
- ${min.version}
- true
- provided
-
org.glassfish.grizzly
grizzly-http
diff --git a/rule/grizzly-http-server/src/main/java/io/opentracing/contrib/specialagent/rule/grizzly/http/server/FilterChainAgentIntercept.java b/rule/grizzly-http-server/src/main/java/io/opentracing/contrib/specialagent/rule/grizzly/http/server/FilterChainAgentIntercept.java
deleted file mode 100644
index 627813d77..000000000
--- a/rule/grizzly-http-server/src/main/java/io/opentracing/contrib/specialagent/rule/grizzly/http/server/FilterChainAgentIntercept.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright 2019 The OpenTracing Authors
- *
- * 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 io.opentracing.contrib.specialagent.rule.grizzly.http.server;
-
-import org.glassfish.grizzly.filterchain.FilterChainBuilder;
-
-import io.opentracing.contrib.grizzly.http.server.TracedFilterChainBuilder;
-import io.opentracing.contrib.specialagent.AgentRuleUtil;
-import io.opentracing.util.GlobalTracer;
-import net.bytebuddy.asm.Advice;
-
-public class FilterChainAgentIntercept {
- public static Object enter(final @Advice.This Object thiz) {
- if (AgentRuleUtil.callerEquals(1, 3, "io.opentracing.contrib.grizzly.http.server.TracedFilterChainBuilder.build"))
- return null;
-
- return new TracedFilterChainBuilder((FilterChainBuilder)thiz, GlobalTracer.get()).build();
- }
-}
\ No newline at end of file
diff --git a/rule/grizzly-http-server/src/main/java/io/opentracing/contrib/specialagent/rule/grizzly/http/server/FilterChainAgentRule.java b/rule/grizzly-http-server/src/main/java/io/opentracing/contrib/specialagent/rule/grizzly/http/server/FilterChainAgentRule.java
deleted file mode 100644
index d7964c0a3..000000000
--- a/rule/grizzly-http-server/src/main/java/io/opentracing/contrib/specialagent/rule/grizzly/http/server/FilterChainAgentRule.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Copyright 2019 The OpenTracing Authors
- *
- * 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 io.opentracing.contrib.specialagent.rule.grizzly.http.server;
-
-import static net.bytebuddy.matcher.ElementMatchers.*;
-
-import io.opentracing.contrib.specialagent.AgentRule;
-import io.opentracing.contrib.specialagent.EarlyReturnException;
-import net.bytebuddy.agent.builder.AgentBuilder;
-import net.bytebuddy.agent.builder.AgentBuilder.Identified.Narrowable;
-import net.bytebuddy.agent.builder.AgentBuilder.Transformer;
-import net.bytebuddy.asm.Advice;
-import net.bytebuddy.description.type.TypeDescription;
-import net.bytebuddy.dynamic.DynamicType.Builder;
-import net.bytebuddy.implementation.bytecode.assign.Assigner.Typing;
-import net.bytebuddy.utility.JavaModule;
-
-public class FilterChainAgentRule extends AgentRule {
- @Override
- public AgentBuilder[] buildAgentUnchained(final AgentBuilder builder) {
- final Narrowable narrowable = builder.type(hasSuperType(named("org.glassfish.grizzly.filterchain.FilterChainBuilder$StatelessFilterChainBuilder")));
- return new AgentBuilder[] {
- narrowable
- .transform(new Transformer() {
- @Override
- public Builder> transform(final Builder> builder, final TypeDescription typeDescription, final ClassLoader classLoader, final JavaModule module) {
- return builder.visit(advice(typeDescription).to(OnEnter.class).on(named("build")));
- }}),
- narrowable
- .transform(new Transformer() {
- @Override
- public Builder> transform(final Builder> builder, final TypeDescription typeDescription, final ClassLoader classLoader, final JavaModule module) {
- return builder.visit(advice(typeDescription).to(OnExit.class).on(named("build")));
- }})};
- }
-
- public static class OnEnter {
- @Advice.OnMethodEnter
- public static void enter(final @ClassName String className, final @Advice.Origin String origin, final @Advice.This Object thiz) throws EarlyReturnException {
- if (!isAllowed(className, origin))
- return;
-
- final Object filterChain = FilterChainAgentIntercept.enter(thiz);
- if (filterChain != null)
- throw new EarlyReturnException(filterChain);
- }
- }
-
- public static class OnExit {
- @SuppressWarnings("unused")
- @Advice.OnMethodExit(onThrowable = Throwable.class)
- public static void exit(@Advice.Return(readOnly = false, typing = Typing.DYNAMIC) Object returned, @Advice.Thrown(readOnly = false, typing = Typing.DYNAMIC) Throwable thrown) {
- if (thrown instanceof EarlyReturnException) {
- returned = ((EarlyReturnException)thrown).getReturnValue();
- thrown = null;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/rule/grizzly-http-server/src/main/java/io/opentracing/contrib/specialagent/rule/grizzly/http/server/HttpServerFilterIntercept.java b/rule/grizzly-http-server/src/main/java/io/opentracing/contrib/specialagent/rule/grizzly/http/server/HttpServerFilterIntercept.java
new file mode 100644
index 000000000..794a62658
--- /dev/null
+++ b/rule/grizzly-http-server/src/main/java/io/opentracing/contrib/specialagent/rule/grizzly/http/server/HttpServerFilterIntercept.java
@@ -0,0 +1,70 @@
+package io.opentracing.contrib.specialagent.rule.grizzly.http.server;
+
+import io.opentracing.Span;
+import io.opentracing.SpanContext;
+import io.opentracing.Tracer;
+import io.opentracing.contrib.grizzly.http.server.GizzlyHttpRequestPacketAdapter;
+import io.opentracing.contrib.grizzly.http.server.GrizzlyServerSpanDecorator;
+import io.opentracing.propagation.Format;
+import io.opentracing.propagation.TextMap;
+import io.opentracing.util.GlobalTracer;
+import org.glassfish.grizzly.filterchain.FilterChainContext;
+import org.glassfish.grizzly.filterchain.NextAction;
+import org.glassfish.grizzly.http.HttpContent;
+import org.glassfish.grizzly.http.HttpRequestPacket;
+import org.glassfish.grizzly.http.HttpResponsePacket;
+
+public class HttpServerFilterIntercept {
+ public static void onHandleReadExit(
+ final Object ctxObj,
+ Object toReturn) {
+
+ FilterChainContext ctx = (FilterChainContext) ctxObj;
+
+ // If not continuing to process
+ // See: org.glassfish.grizzly.filterchain.InvokeAction.TYPE
+ // If we have have already started a span for this request
+ if (!(ctx.getMessage() instanceof HttpContent) || ((NextAction) toReturn).type() != 0 || SpanAssociations.get().hasSpanFor(ctx)) {
+ return;
+ }
+
+ Tracer tracer = GlobalTracer.get();
+ final HttpRequestPacket request = (HttpRequestPacket) ((HttpContent) ctx.getMessage()).getHttpHeader();
+
+ TextMap adapter = new GizzlyHttpRequestPacketAdapter(request);
+ SpanContext extractedContext = tracer.extract(Format.Builtin.HTTP_HEADERS,
+ adapter);
+
+ final Span span = tracer.buildSpan("HTTP::" + request.getMethod().getMethodString())
+ .ignoreActiveSpan()
+ .asChildOf(extractedContext)
+ .start();
+
+ GrizzlyServerSpanDecorator.STANDARD_TAGS.onRequest(request, span);
+ ctx.addCompletionListener(new SpanCompletionListener(span));
+ SpanAssociations.get().associateSpan(ctx, span);
+ }
+
+ public static void onPrepareResponse(
+ final Object ctx,
+ final Object response) {
+ Span toTag = SpanAssociations.get().retrieveSpan(ctx);
+ if (toTag != null) {
+ GrizzlyServerSpanDecorator.STANDARD_TAGS.onResponse((HttpResponsePacket) response, toTag);
+ }
+ }
+
+ public static class SpanCompletionListener implements FilterChainContext.CompletionListener {
+ private final Span span;
+
+ public SpanCompletionListener(Span span) {
+ this.span = span;
+ }
+
+ @Override
+ public void onComplete(FilterChainContext context) {
+ span.finish();
+ SpanAssociations.get().dispose(context);
+ }
+ }
+}
diff --git a/rule/grizzly-http-server/src/main/java/io/opentracing/contrib/specialagent/rule/grizzly/http/server/HttpServerFilterRule.java b/rule/grizzly-http-server/src/main/java/io/opentracing/contrib/specialagent/rule/grizzly/http/server/HttpServerFilterRule.java
new file mode 100644
index 000000000..22d4993a9
--- /dev/null
+++ b/rule/grizzly-http-server/src/main/java/io/opentracing/contrib/specialagent/rule/grizzly/http/server/HttpServerFilterRule.java
@@ -0,0 +1,124 @@
+package io.opentracing.contrib.specialagent.rule.grizzly.http.server;
+
+import io.opentracing.contrib.specialagent.Level;
+import io.opentracing.contrib.specialagent.Logger;
+import io.opentracing.Scope;
+import io.opentracing.contrib.specialagent.AgentRule;
+import net.bytebuddy.agent.builder.AgentBuilder;
+import net.bytebuddy.asm.Advice;
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.dynamic.DynamicType;
+import net.bytebuddy.implementation.bytecode.assign.Assigner;
+import net.bytebuddy.utility.JavaModule;
+
+import static net.bytebuddy.matcher.ElementMatchers.*;
+
+public class HttpServerFilterRule extends AgentRule {
+ public static final Logger logger = Logger.getLogger(HttpServerFilterRule.class);
+ private static final String FILTER_CHAIN_CONTEXT = "org.glassfish.grizzly.filterchain.FilterChainContext";
+ private static final String HANDLE_READ = "handleRead";
+
+ @Override
+ public AgentBuilder buildAgentChainedGlobal1(final AgentBuilder builder) {
+ return builder
+ .type(named("org.glassfish.grizzly.http.HttpServerFilter"))
+ .transform(new AgentBuilder.Transformer() {
+ @Override
+ public DynamicType.Builder> transform(final DynamicType.Builder> builder, final TypeDescription typeDescription, final ClassLoader classLoader, final JavaModule module) {
+ return builder.visit(advice(typeDescription).to(HandleReadAdvice.class).on(named(HANDLE_READ)
+ .and(takesArgument(0, named(FILTER_CHAIN_CONTEXT)))));
+ }
+ })
+ .transform(new AgentBuilder.Transformer() {
+ @Override
+ public DynamicType.Builder> transform(final DynamicType.Builder> builder, final TypeDescription typeDescription, final ClassLoader classLoader, final JavaModule module) {
+ return builder.visit(advice(typeDescription).to(PrepareResponseAdvice.class).on(named("prepareResponse")
+ .and(takesArgument(0, named(FILTER_CHAIN_CONTEXT)))
+ .and(takesArgument(2, named("org.glassfish.grizzly.http.HttpResponsePacket")))));
+ }
+ })
+
+ .type(hasSuperClass(named("org.glassfish.grizzly.filterchain.BaseFilter"))
+ // common http server filters
+ .and(not(named("org.glassfish.grizzly.filterchain.TransportFilter")
+ .or(named("org.glassfish.grizzly.nio.transport.TCPNIOTransportFilter"))
+ .or(named("org.glassfish.grizzly.http.HttpServerFilter"))
+ .or(named("org.glassfish.grizzly.http.HttpCodecFilter"))
+ .or(named("org.glassfish.grizzly.utils.IdleTimeoutFilter"))
+ // common http client filters
+ .or(named("com.ning.http.client.providers.grizzly.AsyncHttpClientFilter"))
+ .or(named("org.glassfish.grizzly.websockets.WebSocketClientFilter"))
+ .or(hasSuperClass(named("org.glassfish.grizzly.http.HttpClientFilter"))))))
+ .transform(new AgentBuilder.Transformer() {
+ @Override
+ public DynamicType.Builder> transform(final DynamicType.Builder> builder, final TypeDescription typeDescription, final ClassLoader classLoader, final JavaModule module) {
+ return builder.visit(advice(typeDescription).to(WorkerHandleReadAdvice.class).on(named(HANDLE_READ)
+ .and(takesArgument(0, named(FILTER_CHAIN_CONTEXT)))));
+ }
+ });
+ }
+
+ public static class HandleReadAdvice {
+ @Advice.OnMethodExit
+ public static void onExit(
+ final @ClassName String className,
+ final @Advice.Origin String origin,
+ @Advice.Argument(0) final Object ctx,
+ @Advice.Return Object toReturn) {
+ if (isAllowed(className, origin))
+ HttpServerFilterIntercept.onHandleReadExit(ctx, toReturn);
+ }
+ }
+
+ public static class WorkerHandleReadAdvice {
+ @Advice.OnMethodEnter
+ public static void onEnter(
+ final @ClassName String className,
+ final @Advice.Origin String origin,
+ final @Advice.This Object thiz,
+ @Advice.Argument(value = 0, typing = Assigner.Typing.DYNAMIC) final Object ctx,
+ @Advice.Local("scope") Scope scope) {
+
+ if (hackShouldFilter(thiz))
+ return;
+
+ if (isAllowed(className, origin))
+ scope = WorkerFilterIntercept.onHandleReadEnter(ctx);
+ }
+
+ @Advice.OnMethodExit
+ public static void onExit(
+ final @ClassName String className,
+ final @Advice.Origin String origin,
+ final @Advice.This Object thiz,
+ @Advice.Local("scope") Scope scope) {
+
+ if (hackShouldFilter(thiz))
+ return;
+
+ if (isAllowed(className, origin))
+ WorkerFilterIntercept.onHandleReadExit(scope);
+ }
+ }
+
+ public static class PrepareResponseAdvice {
+ @Advice.OnMethodExit
+ public static void onExit(
+ final @ClassName String className,
+ final @Advice.Origin String origin,
+ @Advice.Argument(value = 0, typing = Assigner.Typing.DYNAMIC) final Object ctx,
+ @Advice.Argument(value = 2, typing = Assigner.Typing.DYNAMIC) final Object response) {
+
+ if (isAllowed(className, origin))
+ HttpServerFilterIntercept.onPrepareResponse(ctx, response);
+ }
+
+ }
+
+ public static boolean hackShouldFilter(Object thiz) {
+ // TODO: 7/11/20 figure out why these are not filtered at TypeDescription
+ logger.log(Level.FINER, "Checking predicate for potential worker filter " + thiz.getClass().getName());
+ return "com.ning.http.client.providers.grizzly.AsyncHttpClientFilter".equals(thiz.getClass().getName()) ||
+ "org.glassfish.grizzly.websockets.WebSocketClientFilter".equals(thiz.getClass().getName());
+ }
+}
diff --git a/rule/grizzly-http-server/src/main/java/io/opentracing/contrib/specialagent/rule/grizzly/http/server/SpanAssociations.java b/rule/grizzly-http-server/src/main/java/io/opentracing/contrib/specialagent/rule/grizzly/http/server/SpanAssociations.java
new file mode 100644
index 000000000..fe90f66ef
--- /dev/null
+++ b/rule/grizzly-http-server/src/main/java/io/opentracing/contrib/specialagent/rule/grizzly/http/server/SpanAssociations.java
@@ -0,0 +1,71 @@
+/* Copyright 2020 The OpenTracing Authors
+ *
+ * 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 io.opentracing.contrib.specialagent.rule.grizzly.http.server;
+
+import io.opentracing.Span;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * This class provides span context capabilities. Based on
+ * https://github.com/opentracing-contrib/java-agent/blob/release-0.5.0/opentracing-agent/src/main/java/io/opentracing/contrib/agent/OpenTracingHelper.java
+ */
+public class SpanAssociations {
+
+ private static final SpanAssociations INSTANCE = new SpanAssociations();
+ private static final Map