From d3bb9f1f73a90210e0e38069a63db816d99b819c Mon Sep 17 00:00:00 2001 From: Vladimir Pankrashkin Date: Wed, 27 Apr 2016 19:03:48 +0300 Subject: [PATCH 1/5] MSPF-16: Api client part --- pom.xml | 18 ++ woody-api/pom.xml | 37 ++++ .../woody/api/AbstractClientBuilder.java | 147 ++++++++++++++++ .../com/rbkmoney/woody/api/ClientBuilder.java | 22 +++ .../rbkmoney/woody/api/ServiceBuilder.java | 18 ++ .../woody/api/ServiceConfigurator.java | 8 + .../woody/api/event/ClientEventListener.java | 12 ++ .../woody/api/event/ClientEventType.java | 12 ++ .../rbkmoney/woody/api/event/ErrorType.java | 10 ++ .../woody/api/event/EventListener.java | 12 ++ .../woody/api/event/ServiceEventListener.java | 12 ++ .../woody/api/event/ServiceEventType.java | 12 ++ .../woody/api/generator/IdGenerator.java | 12 ++ .../api/provider/ClientProviderControl.java | 8 + .../api/proxy/HandleMethodCallerFactory.java | 82 +++++++++ .../woody/api/proxy/InstanceMethodCaller.java | 9 + .../api/proxy/MethodCallInterceptor.java | 9 + .../api/proxy/MethodCallInterceptors.java | 24 +++ .../woody/api/proxy/MethodCallTracer.java | 12 ++ .../woody/api/proxy/MethodCallerFactory.java | 10 ++ .../woody/api/proxy/MethodShadow.java | 89 ++++++++++ .../woody/api/proxy/ProxyFactory.java | 49 ++++++ .../api/proxy/ProxyInvocationHandler.java | 42 +++++ .../proxy/ReflectionMethodCallerFactory.java | 14 ++ .../woody/api/trace/AbstractSpan.java | 30 ++++ .../rbkmoney/woody/api/trace/ClientSpan.java | 8 + .../rbkmoney/woody/api/trace/Endpoint.java | 10 ++ .../rbkmoney/woody/api/trace/Metadata.java | 41 +++++ .../woody/api/trace/MetadataProperties.java | 13 ++ .../rbkmoney/woody/api/trace/ServerSpan.java | 29 ++++ .../com/rbkmoney/woody/api/trace/Span.java | 90 ++++++++++ .../rbkmoney/woody/api/trace/TraceData.java | 66 +++++++ .../api/trace/context/ContextTracer.java | 41 +++++ .../trace/context/EventListenerTracer.java | 51 ++++++ .../api/trace/context/MetadataTracer.java | 86 ++++++++++ .../woody/api/trace/context/TraceContext.java | 161 ++++++++++++++++++ .../interceptor/ClientRequestInterceptor.java | 9 + .../ClientResponseInterceptor.java | 9 + .../interceptor/RequestInterceptor.java | 10 ++ .../interceptor/ResponseInterceptor.java | 10 ++ .../interceptor/ServerRequestInterceptor.java | 9 + .../interceptor/ServerResponseIntercepor.java | 9 + .../WrappedRequestInterceptor.java | 36 ++++ .../api/proxy/TestProxyInvocationFactory.java | 101 +++++++++++ woody-thrift/pom.xml | 15 ++ .../rbkmoney/woody/thrift/ErrorCallType.java | 24 +++ .../http/transport/TransportErrorType.java | 11 ++ 47 files changed, 1549 insertions(+) create mode 100644 pom.xml create mode 100644 woody-api/pom.xml create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/AbstractClientBuilder.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/ClientBuilder.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/ServiceBuilder.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/ServiceConfigurator.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEventListener.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEventType.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/event/ErrorType.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/event/EventListener.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventListener.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventType.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/generator/IdGenerator.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/provider/ClientProviderControl.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/proxy/HandleMethodCallerFactory.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/proxy/InstanceMethodCaller.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallInterceptor.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallInterceptors.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallTracer.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallerFactory.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodShadow.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ProxyFactory.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ProxyInvocationHandler.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ReflectionMethodCallerFactory.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/trace/AbstractSpan.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/trace/ClientSpan.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/trace/Endpoint.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/trace/Metadata.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/trace/MetadataProperties.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/trace/ServerSpan.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/trace/Span.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/trace/TraceData.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/ContextTracer.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/EventListenerTracer.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/MetadataTracer.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/TraceContext.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientRequestInterceptor.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientResponseInterceptor.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/RequestInterceptor.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ResponseInterceptor.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerRequestInterceptor.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerResponseIntercepor.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/WrappedRequestInterceptor.java create mode 100644 woody-api/src/test/java/com/rbkmoney/woody/api/proxy/TestProxyInvocationFactory.java create mode 100644 woody-thrift/pom.xml create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/ErrorCallType.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/TransportErrorType.java diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..577bfec --- /dev/null +++ b/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + pom + com.rbkmoney.woody + woody + 1.0.0 + Java implementation for Woody spec + + + woody-api + woody-thrift + + + + \ No newline at end of file diff --git a/woody-api/pom.xml b/woody-api/pom.xml new file mode 100644 index 0000000..f84b514 --- /dev/null +++ b/woody-api/pom.xml @@ -0,0 +1,37 @@ + + + + woody + com.rbkmoney.woody + 1.0.0 + + 4.0.0 + + woody-api + + + + junit + junit + 4.11 + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + + + \ No newline at end of file diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/AbstractClientBuilder.java b/woody-api/src/main/java/com/rbkmoney/woody/api/AbstractClientBuilder.java new file mode 100644 index 0000000..7769b14 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/AbstractClientBuilder.java @@ -0,0 +1,147 @@ +package com.rbkmoney.woody.api; + +import com.rbkmoney.woody.api.event.ClientEventListener; +import com.rbkmoney.woody.api.generator.IdGenerator; +import com.rbkmoney.woody.api.provider.ClientProviderControl; +import com.rbkmoney.woody.api.proxy.MethodCallTracer; +import com.rbkmoney.woody.api.proxy.ProxyFactory; +import com.rbkmoney.woody.api.trace.context.ContextTracer; +import com.rbkmoney.woody.api.trace.context.EventListenerTracer; +import com.rbkmoney.woody.api.trace.context.MetadataTracer; +import com.rbkmoney.woody.api.trace.context.TraceContext; + +import java.net.URI; + +/** + * Created by vpankrashkin on 25.04.16. + */ +public abstract class AbstractClientBuilder implements ClientBuilder { + private URI address; + private ClientEventListener eventListener; + private IdGenerator idGenerator; + + @Override + public ClientBuilder withAddress(URI address) { + this.address = address; + return this; + } + + @Override + public ClientBuilder withEventListener(ClientEventListener listener) { + this.eventListener = listener; + return this; + } + + @Override + public ClientBuilder withIdGenerator(IdGenerator generator) { + this.idGenerator = generator; + return this; + } + + @Override + public T build(Class clientInterface) { + return createProxyClient(clientInterface, null); + } + + @Override + public T build(Class clientInterface, ClientProviderControl providerControl) { + T target = null; + return createProxyClient(clientInterface, target); + } + + protected T createProxyClient(Class clientInterface, T target) { + ProxyBuilder proxyBuilder = new ProxyBuilder(); + proxyBuilder.setIdGenerator(idGenerator); + proxyBuilder.setStartEventListener(getEventStartListener(eventListener)); + proxyBuilder.setEndEventListener(getEventEndListener(eventListener)); + proxyBuilder.setErrEventListener(getErrorListener(eventListener)); + proxyBuilder.setStartEventPhases(ProxyBuilder.BEFORE_CALL_START); + proxyBuilder.setEndEventPhases(ProxyBuilder.BEFORE_CONTEXT_DESTROY); + return proxyBuilder.build(clientInterface, target); + + } + + abstract protected Runnable getErrorListener(ClientEventListener eventListener); + + abstract protected Runnable getEventStartListener(ClientEventListener eventListener); + + abstract protected Runnable getEventEndListener(ClientEventListener eventListener); + + abstract T createProxyTarget(Class clientInterface, ClientEventListener listener, ClientProviderControl providerControl); + + protected static class ProxyBuilder { + private static final int AFTER_CONTEXT_INIT = 0b01; + private static final int BEFORE_CONTEXT_DESTROY = 0b10; + private static final int BEFORE_CALL_START = 0b100; + private static final int AFTER_CALL_END = 0b1000; + + private int startEventPhases; + private int endEventPhases; + private boolean allowObjectOverriding = false; + + private final Runnable stub = () -> { + }; + private Runnable startEventListener; + private Runnable endEventListener; + private Runnable errEventListener; + private IdGenerator idGenerator; + + public void setStartEventListener(Runnable startEventListener) { + this.startEventListener = startEventListener; + } + + public void setEndEventListener(Runnable endEventListener) { + this.endEventListener = endEventListener; + } + + public void setErrEventListener(Runnable errEventListener) { + this.errEventListener = errEventListener; + } + + public void setIdGenerator(IdGenerator idGenerator) { + this.idGenerator = idGenerator; + } + + public void setAllowObjectOverriding(boolean allowObjectOverriding) { + this.allowObjectOverriding = allowObjectOverriding; + } + + public void setStartEventPhases(int phases) { + startEventPhases = phases; + } + + public void setEndEventPhases(int phases) { + endEventPhases = phases; + } + + public ProxyFactory createProxyFactory() { + return new ProxyFactory(createMethodCallTracer(), allowObjectOverriding); + } + + public MethodCallTracer createMethodCallTracer() { + return new ContextTracer(createTraceContext(), createEventTracer()); + } + + public TraceContext createTraceContext() { + return TraceContext.forClient(idGenerator, + hasFlag(AFTER_CONTEXT_INIT, startEventPhases) ? startEventListener : stub, + hasFlag(BEFORE_CONTEXT_DESTROY, endEventPhases) ? endEventListener : startEventListener); + } + + public EventListenerTracer createEventTracer() { + return new EventListenerTracer(MetadataTracer.forClient(), + hasFlag(BEFORE_CALL_START, startEventPhases) ? startEventListener : stub, + hasFlag(AFTER_CALL_END, endEventPhases) ? endEventListener : stub, + errEventListener); + } + + public T build(Class clientInterface, T target) { + ProxyFactory proxyFactory = createProxyFactory(); + return proxyFactory.getInstance(clientInterface, target); + } + + private boolean hasFlag(int test, int flags) { + return (test & flags) != 0; + } + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/ClientBuilder.java b/woody-api/src/main/java/com/rbkmoney/woody/api/ClientBuilder.java new file mode 100644 index 0000000..dfcb0c2 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/ClientBuilder.java @@ -0,0 +1,22 @@ +package com.rbkmoney.woody.api; + +import com.rbkmoney.woody.api.event.ClientEventListener; +import com.rbkmoney.woody.api.generator.IdGenerator; +import com.rbkmoney.woody.api.provider.ClientProviderControl; + +import java.net.URI; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public interface ClientBuilder { + ClientBuilder withAddress(URI address); + + ClientBuilder withEventListener(ClientEventListener listener); + + ClientBuilder withIdGenerator(IdGenerator generator); + + T build(Class clientInterface); + + T build(Class clientInterface, ClientProviderControl configurator); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/ServiceBuilder.java b/woody-api/src/main/java/com/rbkmoney/woody/api/ServiceBuilder.java new file mode 100644 index 0000000..1557635 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/ServiceBuilder.java @@ -0,0 +1,18 @@ +package com.rbkmoney.woody.api; + +import com.rbkmoney.woody.api.generator.IdGenerator; + +import java.beans.EventHandler; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public interface ServiceBuilder { + ServiceBuilder withEventHandler(EventHandler handler); + + ServiceBuilder withIdGenerator(IdGenerator generator); + + T build(Class serviceInterface); + + T build(Class serviceInterface, ServiceConfigurator configurator); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/ServiceConfigurator.java b/woody-api/src/main/java/com/rbkmoney/woody/api/ServiceConfigurator.java new file mode 100644 index 0000000..920bc63 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/ServiceConfigurator.java @@ -0,0 +1,8 @@ +package com.rbkmoney.woody.api; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public interface ServiceConfigurator { + void configure(T serviceProvider); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEventListener.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEventListener.java new file mode 100644 index 0000000..e1a73be --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEventListener.java @@ -0,0 +1,12 @@ +package com.rbkmoney.woody.api.event; + +import com.rbkmoney.woody.api.trace.TraceData; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public interface ClientEventListener extends EventListener { + void notifyEvent(ClientEventType eventType, TraceData traceData); + + void notifyError(ErrorType errorType, TraceData traceData); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEventType.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEventType.java new file mode 100644 index 0000000..7dfc7ac --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEventType.java @@ -0,0 +1,12 @@ +package com.rbkmoney.woody.api.event; + +/** + * Created by vpankrashkin on 25.04.16. + */ +public enum ClientEventType { + CALL_SERVICE, + CLIENT_SEND, + CLIENT_RECEIVE, + SERVICE_RESULT, + ERROR +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ErrorType.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ErrorType.java new file mode 100644 index 0000000..7b1c548 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ErrorType.java @@ -0,0 +1,10 @@ +package com.rbkmoney.woody.api.event; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public enum ErrorType { + UNKNOWN_CALL, + TRANSPORT, + ERROR_CALL +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/EventListener.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/EventListener.java new file mode 100644 index 0000000..7983d34 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/EventListener.java @@ -0,0 +1,12 @@ +package com.rbkmoney.woody.api.event; + +import com.rbkmoney.woody.api.trace.TraceData; + +/** + * Created by vpankrashkin on 25.04.16. + */ +public interface EventListener { + void notifyEvent(EvnT eventType, TraceData traceData); + + void notifyError(ErrT errorType, TraceData traceData); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventListener.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventListener.java new file mode 100644 index 0000000..50bdac3 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventListener.java @@ -0,0 +1,12 @@ +package com.rbkmoney.woody.api.event; + +import com.rbkmoney.woody.api.trace.TraceData; + +/** + * Created by vpankrashkin on 25.04.16. + */ +public interface ServiceEventListener extends EventListener { + void notifyEvent(ServiceEventType eventType, TraceData traceData); + + void notifyError(ErrorType errorType, TraceData traceData); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventType.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventType.java new file mode 100644 index 0000000..90167e8 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventType.java @@ -0,0 +1,12 @@ +package com.rbkmoney.woody.api.event; + +/** + * Created by vpankrashkin on 25.04.16. + */ +public enum ServiceEventType { + SERVICE_RECEIVE, + CALL_HANDLER, + HANDLER_RESULT, + SERVICE_RESULT, + ERROR +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/generator/IdGenerator.java b/woody-api/src/main/java/com/rbkmoney/woody/api/generator/IdGenerator.java new file mode 100644 index 0000000..e76bb1f --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/generator/IdGenerator.java @@ -0,0 +1,12 @@ +package com.rbkmoney.woody.api.generator; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public interface IdGenerator { + String NO_PARENT_ID = "undefined"; + + String generateId(long timestamp); + + String generateId(long timestamp, int counter); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/provider/ClientProviderControl.java b/woody-api/src/main/java/com/rbkmoney/woody/api/provider/ClientProviderControl.java new file mode 100644 index 0000000..5cab80a --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/provider/ClientProviderControl.java @@ -0,0 +1,8 @@ +package com.rbkmoney.woody.api.provider; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public interface ClientProviderControl { + void configure(T clientProvider); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/HandleMethodCallerFactory.java b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/HandleMethodCallerFactory.java new file mode 100644 index 0000000..c12f3d5 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/HandleMethodCallerFactory.java @@ -0,0 +1,82 @@ +package com.rbkmoney.woody.api.proxy; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Method; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public class HandleMethodCallerFactory implements MethodCallerFactory { + + @Override + public InstanceMethodCaller getInstance(Object target, Method method) { + + + try { + MethodHandle mh = MethodHandles.lookup() + .findVirtual(target.getClass(), method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes())).asSpreader(Object[].class, method.getParameterCount()); + + return new InstanceMethodCaller() { + @Override + public Object call(Object[] args) throws Throwable { + + return mh.invokeWithArguments(target, args) + ; + //.unreflectSpecial(method, target.getClass()) + + //.invokeWithArguments(args); + //.bindTo(target) + //.invokeWithArguments(args); + + } + }; + + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + private Object[] createArgList(Object target, Object[] args) { + if (args == null || args.length == 0) { + return new Object[]{target}; + } else { + Object[] mArgs = new Object[args.length + 1]; + { + mArgs[0] = target; + System.arraycopy(args, 0, mArgs, 1, args.length); + return mArgs; + } + } + + } +// @Override +// public InstanceMethodCaller getInstance(Object target, Method method) { +// +// +// try { +// // 1. Retrieves a Lookup +// MethodHandles.Lookup lookup = MethodHandles.lookup(); +// +// MethodHandle handle=lookup.unreflect(method); +// +// +// // 4. Invoke the method +// return new InstanceMethodCaller() { +// @Override +// public Object call(Object[] args) throws Throwable { +// return handle.invokeWithArguments(args); +// } +// }; +// //return args -> handle.invokeWithArguments(args); +// // ^----^ ^----^ +// // | argument +// // instance of FooBar to invoke the method on +// }catch ( IllegalAccessException e) { +// e.printStackTrace(); +// throw new RuntimeException(e); +// } +// } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/InstanceMethodCaller.java b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/InstanceMethodCaller.java new file mode 100644 index 0000000..7cde75c --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/InstanceMethodCaller.java @@ -0,0 +1,9 @@ +package com.rbkmoney.woody.api.proxy; + +/** + * Created by vpankrashkin on 22.04.16. + */ +@FunctionalInterface +public interface InstanceMethodCaller { + Object call(Object[] args) throws Throwable; +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallInterceptor.java new file mode 100644 index 0000000..49ac1d6 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallInterceptor.java @@ -0,0 +1,9 @@ +package com.rbkmoney.woody.api.proxy; + +/** + * Created by vpankrashkin on 22.04.16. + */ +@FunctionalInterface +public interface MethodCallInterceptor { + Object intercept(Object[] args, InstanceMethodCaller caller) throws Throwable; +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallInterceptors.java b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallInterceptors.java new file mode 100644 index 0000000..d8e90ea --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallInterceptors.java @@ -0,0 +1,24 @@ +package com.rbkmoney.woody.api.proxy; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public class MethodCallInterceptors { + public static MethodCallInterceptor directCallInterceptor() { + return (args, caller) -> caller.call(args); + } + + public static MethodCallInterceptor trackedCallInterceptor(MethodCallTracer callTracer) { + return (args, caller) -> { + callTracer.beforeCall(args, caller); + try { + Object result = caller.call(args); + callTracer.afterCall(args, caller, result); + return result; + } catch (Throwable t) { + callTracer.callError(args, caller, t); + throw t; + } + }; + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallTracer.java b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallTracer.java new file mode 100644 index 0000000..9ba6550 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallTracer.java @@ -0,0 +1,12 @@ +package com.rbkmoney.woody.api.proxy; + +/** + * Created by vpankrashkin on 23.04.16. + */ +public interface MethodCallTracer { + void beforeCall(Object[] args, InstanceMethodCaller caller); + + void afterCall(Object[] args, InstanceMethodCaller caller, Object result); + + void callError(Object[] args, InstanceMethodCaller caller, Throwable error); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallerFactory.java b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallerFactory.java new file mode 100644 index 0000000..e36af14 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallerFactory.java @@ -0,0 +1,10 @@ +package com.rbkmoney.woody.api.proxy; + +import java.lang.reflect.Method; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public interface MethodCallerFactory { + InstanceMethodCaller getInstance(Object target, Method method); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodShadow.java b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodShadow.java new file mode 100644 index 0000000..384b1e7 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodShadow.java @@ -0,0 +1,89 @@ +package com.rbkmoney.woody.api.proxy; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.stream.Stream; + +import static java.lang.reflect.Modifier.isPrivate; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public class MethodShadow { + + public static Method[] getShadowedMethods(Class ifaceA, Collection ifacesB) { + for (Class ifaceB : ifacesB) { + Method[] shadowedMethods = getShadowedMethods(ifaceA, ifaceB); + if (shadowedMethods.length != 0) { + return shadowedMethods; + } + } + return new Method[0]; + } + + public static Method[] getShadowedMethods(Class ifaceA, Class ifaceB) { + Stream.of(ifaceA, ifaceB).forEach(iface -> checkInterface(iface, "Referred class is not an interface:")); + + return getOverlappingMethods(ifaceA.getMethods(), ifaceB.getMethods()); + } + + public static Method[] getShadowedMethods(Object object, Class iface) { + checkInterface(iface, "Referred class is not an interface:"); + Method[] objMethods = Arrays.stream(object.getClass().getMethods()).filter(m -> { + int mod = m.getModifiers(); + return !(isPrivate(mod)); + }).toArray(Method[]::new); + + return getOverlappingMethods(objMethods, iface.getMethods()); + + } + + public static boolean isSameSignature(Method methodA, Method methodB) { + return METHOD_COMPARATOR.compare(methodA, methodB) == 0; + } + + public static Method[] getOverlappingMethods(Method[] aMethods, Method[] bMethods) { + return Arrays.stream(aMethods) + .filter(tm -> Arrays.stream(bMethods) + .filter(sm -> isSameSignature(tm, sm)) + .findAny().isPresent()) + .toArray(Method[]::new); + } + + public static Method getSameMethod(Method searchMethod, Class targetClass) { + try { + return targetClass.getMethod(searchMethod.getName(), searchMethod.getParameterTypes()); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static void checkInterface(Class cl, String errorMessage) { + if (!cl.isInterface()) { + throw new IllegalArgumentException(errorMessage + cl.getName()); + } + } + + public static final Comparator METHOD_COMPARATOR = (m1, m2) -> { + + int currResult = m1.getName().compareTo(m2.getName()); + if (currResult != 0) { + return currResult; + } + currResult = m1.getParameterCount() - m2.getParameterCount(); + if (currResult != 0) { + return currResult; + } + + Class[] pt1 = m1.getParameterTypes(); + Class[] pt2 = m2.getParameterTypes(); + + for (int i = 0; i < pt1.length; i++) { + if (pt1[i] != pt2[i]) + return pt1[i].hashCode() - pt2[i].hashCode(); + } + return 0; + }; +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ProxyFactory.java b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ProxyFactory.java new file mode 100644 index 0000000..51d9442 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ProxyFactory.java @@ -0,0 +1,49 @@ +package com.rbkmoney.woody.api.proxy; + +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public class ProxyFactory { + private final Object object = new Object(); + private final MethodCallerFactory callerFactory; + private final MethodCallTracer callTracer; + private final boolean allowObjectOverriding; + + public ProxyFactory(MethodCallTracer callTracer, boolean allowObjectOverriding) { + this(new ReflectionMethodCallerFactory(), callTracer, allowObjectOverriding); + } + + public ProxyFactory(MethodCallerFactory callerFactory, MethodCallTracer callTracer, boolean allowObjectOverriding) { + this.callerFactory = callerFactory; + this.callTracer = callTracer; + this.allowObjectOverriding = allowObjectOverriding; + } + + public T getInstance(Class iface, T target) { + return getInstance(iface, target, callerFactory, callTracer, allowObjectOverriding); + } + + @SuppressWarnings("unchecked") + public T getInstance(Class iface, T target, MethodCallerFactory callerFactory, MethodCallTracer callTracer, boolean allowObjectOverriding) { + if (!allowObjectOverriding) { + Method[] overriden = MethodShadow.getShadowedMethods(object, iface); + if (overriden.length != 0) { + throw new IllegalArgumentException("Target interface " + iface.getName() + "shadows Object methods:" + overriden); + } + } + return makeProxy(target, iface, callerFactory, callTracer); + + } + + protected T makeProxy(T target, Class iface, MethodCallerFactory callerFactory, MethodCallTracer callTracer) { + + return (T) Proxy.newProxyInstance( + iface.getClassLoader(), + new Class[]{iface}, + new ProxyInvocationHandler(target, iface, callerFactory, MethodCallInterceptors.trackedCallInterceptor(callTracer))); + + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ProxyInvocationHandler.java b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ProxyInvocationHandler.java new file mode 100644 index 0000000..227ca54 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ProxyInvocationHandler.java @@ -0,0 +1,42 @@ +package com.rbkmoney.woody.api.proxy; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.TreeMap; + +public class ProxyInvocationHandler implements InvocationHandler { + + private final Map callMap; + private final MethodCallInterceptor callInterceptor; + private final Object target; + + public ProxyInvocationHandler(Object target, Class iface, MethodCallerFactory callerFactory, MethodCallInterceptor callInterceptor) { + this.callMap = createCallMap(target, iface, callerFactory); + this.callInterceptor = callInterceptor; + this.target = target; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + InstanceMethodCaller methodCaller = callMap.get(method); + if (methodCaller != null) { + return callInterceptor.intercept(args, callMap.get(method)); + } else { + return method.invoke(target, args); + } + } + + private Map createCallMap(Object target, Class iface, MethodCallerFactory callerFactory) { + if (!iface.isAssignableFrom(target.getClass())) { + throw new IllegalArgumentException("Target object class doesn't implement referred interface"); + } + Map callerMap = new TreeMap<>(MethodShadow.METHOD_COMPARATOR); + Method[] targetIfaceMethods = MethodShadow.getShadowedMethods(target, iface); + + for (Method method : targetIfaceMethods) { + callerMap.put(MethodShadow.getSameMethod(method, iface), callerFactory.getInstance(target, method)); + } + return callerMap; + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ReflectionMethodCallerFactory.java b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ReflectionMethodCallerFactory.java new file mode 100644 index 0000000..431e79a --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ReflectionMethodCallerFactory.java @@ -0,0 +1,14 @@ +package com.rbkmoney.woody.api.proxy; + +import java.lang.reflect.Method; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public class ReflectionMethodCallerFactory implements MethodCallerFactory { + @Override + public InstanceMethodCaller getInstance(Object target, Method method) { + method.setAccessible(true); + return (args) -> method.invoke(target, args); + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/AbstractSpan.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/AbstractSpan.java new file mode 100644 index 0000000..28f9755 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/AbstractSpan.java @@ -0,0 +1,30 @@ +package com.rbkmoney.woody.api.trace; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public class AbstractSpan { + protected final Span span = new Span(); + protected final Metadata metadata = new Metadata(); + + public Span getSpan() { + return span; + } + + public Metadata getMetadata() { + return metadata; + } + + public boolean isFilled() { + return span.isFilled(); + } + + public boolean isStarted() { + return span.isStarted(); + } + + public void reset() { + span.reset(); + metadata.reset(); + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ClientSpan.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ClientSpan.java new file mode 100644 index 0000000..a1a2b4d --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ClientSpan.java @@ -0,0 +1,8 @@ +package com.rbkmoney.woody.api.trace; + +/** + * Created by vpankrashkin on 21.04.16. + */ +public class ClientSpan extends AbstractSpan { + +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Endpoint.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Endpoint.java new file mode 100644 index 0000000..3eecb84 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Endpoint.java @@ -0,0 +1,10 @@ +package com.rbkmoney.woody.api.trace; + +/** + * Created by vpankrashkin on 21.04.16. + */ +public interface Endpoint { + S getSource(); + + T getTarget(); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Metadata.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Metadata.java new file mode 100644 index 0000000..f2e4d1f --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Metadata.java @@ -0,0 +1,41 @@ +package com.rbkmoney.woody.api.trace; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Created by vpankrashkin on 21.04.16. + */ +public class Metadata { + private static final int DEFAULT_INIT_SIZE = 8; + private static final float DEFAULT_LOAD_FACTOR = 0.75f; + + private Map values = createStore(DEFAULT_INIT_SIZE, DEFAULT_LOAD_FACTOR); + + public T getValue(String key) { + return (T) values.get(key); + } + + public T removeValue(String key) { + return (T) values.remove(key); + } + + public T putValue(String key, Object value) { + return (T) values.put(key, value); + } + + public Collection getKeys() { + return values.keySet(); + } + + + public void reset() { + values = createStore(DEFAULT_INIT_SIZE, DEFAULT_LOAD_FACTOR); + } + + private static Map createStore(int size, float loadFactor) { + return new HashMap<>(size, loadFactor); + } + +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/MetadataProperties.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/MetadataProperties.java new file mode 100644 index 0000000..6833f41 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/MetadataProperties.java @@ -0,0 +1,13 @@ +package com.rbkmoney.woody.api.trace; + +/** + * Created by vpankrashkin on 25.04.16. + */ +public class MetadataProperties { + public static final String CALL_ARGUMENTS = "md_call_arguments"; + public static final String INSTANCE_METHOD_CALLER = "md_instance_method_caller"; + public static final String CALL_RESULT = "md_call_result"; + public static final String CALL_ERROR = "md_call_error"; + + public static final String EVENT_TYPE = "md_event_type"; +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ServerSpan.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ServerSpan.java new file mode 100644 index 0000000..53e0ac9 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ServerSpan.java @@ -0,0 +1,29 @@ +package com.rbkmoney.woody.api.trace; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Created by vpankrashkin on 21.04.16. + */ +public class ServerSpan extends AbstractSpan { + private Endpoint endpoint; + private final AtomicInteger counter = new AtomicInteger(); + + public Endpoint getEndpoint() { + return endpoint; + } + + public void setEndpoint(Endpoint endpoint) { + this.endpoint = endpoint; + } + + public AtomicInteger getCounter() { + return counter; + } + + public void reset() { + super.reset(); + endpoint = null; + counter.set(0); + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Span.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Span.java new file mode 100644 index 0000000..1019b71 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Span.java @@ -0,0 +1,90 @@ +package com.rbkmoney.woody.api.trace; + +/** + * Created by vpankrashkin on 21.04.16. + */ +public class Span { + private String traceId; + private String name; + private String id; + private String parentId; + private long timestamp; + private long duration; + + public String getTraceId() { + return traceId; + } + + public void setTraceId(String traceId) { + this.traceId = traceId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getParentId() { + return parentId; + } + + public void setParentId(String parentId) { + this.parentId = parentId; + } + + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + public boolean isFilled() { + return traceId != null; + } + + public boolean isStarted() { + return isFilled() && timestamp != 0; + } + + public void reset() { + traceId = null; + name = null; + id = null; + parentId = null; + timestamp = 0; + duration = 0; + } + + @Override + public String toString() { + return "Span{" + + "traceId='" + traceId + '\'' + + ", name='" + name + '\'' + + ", id='" + id + '\'' + + ", parentId='" + parentId + '\'' + + ", timestamp=" + timestamp + + ", duration=" + duration + + '}'; + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/TraceData.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/TraceData.java new file mode 100644 index 0000000..4e1bcbb --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/TraceData.java @@ -0,0 +1,66 @@ +package com.rbkmoney.woody.api.trace; + +/** + * Created by vpankrashkin on 21.04.16. + */ +public class TraceData { + private ClientSpan clientSpan = new ClientSpan(); + private ServerSpan serverSpan = new ServerSpan(); + + public ClientSpan getClientSpan() { + return clientSpan; + } + + public ServerSpan getServerSpan() { + return serverSpan; + } + + /** + * Checks if {@link ServerSpan} is filled to determine root: + * - request initialized by server: span must be filled by server with data referred from client: has filled server span, it's not root by default -> false + * - request initialized by client, produced by any server request handling event: has filled server span, it's not root -> false + * - request initialized by client, not produced by any server request handling event: server span not filled, it's root -> true + * + * @return true - if root call is running; false - otherwise + */ + public boolean isRoot() { + return !serverSpan.isFilled(); + } + + /** + * Checks combination of client and server spans to determine current state: + * Consider this states scheme (S - server span, C - client span; 1 - if it's set, 0 - if not set, determined by checking traceId existence in corresponding span): + *

+ * S | C + * ----- + * 0 | 0 + * 0 | 1 + * 1 | 0 + * 1 | 1 + *

+ * 0,0 and 0,1 combinations don't have server span and context in the state can't be server by default (no server span is set) - it's client state -> true + * 1,0 means that server span is created and no client span exists - it's server state -> false + * 1,1 means that both spans exist and child client call is active now because for any client request client span is cleared after call completion, so after child call state returns to (1,0) case - (1,1) is child client state -> true + *

+ * This allows to eliminate the necessity for call processing code to be explicitly configured with expected call state. This can be figured out directly from the context in runtime. + * The only exclusion is {@link com.rbkmoney.woody.api.trace.context.TraceContext} itself. It uses already filled trace id field for server state initiazation + * + * @return true - if call is running as root client or child client call for server request handling; false - if call is running in server request handing + */ + public boolean isClient() { + return serverSpan.isFilled() ? clientSpan.isFilled() : true; + } + + public AbstractSpan getActiveSpan() { + return isClient() ? clientSpan : serverSpan; + } + + public AbstractSpan getSpan(boolean isClient) { + return isClient ? clientSpan : serverSpan; + } + + public void reset() { + clientSpan.reset(); + serverSpan.reset(); + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/ContextTracer.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/ContextTracer.java new file mode 100644 index 0000000..9616132 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/ContextTracer.java @@ -0,0 +1,41 @@ +package com.rbkmoney.woody.api.trace.context; + +import com.rbkmoney.woody.api.proxy.InstanceMethodCaller; +import com.rbkmoney.woody.api.proxy.MethodCallTracer; + +/** + * Created by vpankrashkin on 26.04.16. + */ +public class ContextTracer implements MethodCallTracer { + private final TraceContext traceContext; + private final MethodCallTracer targetTracer; + + public ContextTracer(TraceContext traceContext, MethodCallTracer targetTracer) { + this.traceContext = traceContext; + this.targetTracer = targetTracer; + } + + @Override + public void beforeCall(Object[] args, InstanceMethodCaller caller) { + traceContext.init(); + targetTracer.beforeCall(args, caller); + } + + @Override + public void afterCall(Object[] args, InstanceMethodCaller caller, Object result) { + try { + targetTracer.afterCall(args, caller, result); + } finally { + traceContext.destroy(); + } + } + + @Override + public void callError(Object[] args, InstanceMethodCaller caller, Throwable error) { + try { + targetTracer.callError(args, caller, error); + } finally { + traceContext.destroy(); + } + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/EventListenerTracer.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/EventListenerTracer.java new file mode 100644 index 0000000..51137b3 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/EventListenerTracer.java @@ -0,0 +1,51 @@ +package com.rbkmoney.woody.api.trace.context; + + +import com.rbkmoney.woody.api.proxy.InstanceMethodCaller; +import com.rbkmoney.woody.api.proxy.MethodCallTracer; + +/** + * Created by vpankrashkin on 25.04.16. + */ +public class EventListenerTracer implements MethodCallTracer { + + private final MethodCallTracer callTracer; + private final Runnable beforeCallListener; + private final Runnable afterCallListener; + private final Runnable errListener; + + public EventListenerTracer(MethodCallTracer callTracer) { + this(callTracer, null, null, null); + } + + public EventListenerTracer(MethodCallTracer callTracer, Runnable beforeCallListener, Runnable afterCallListener, Runnable errListener) { + if (callTracer == null) { + throw new NullPointerException("Tracer or listener cannot be null"); + } + this.callTracer = callTracer; + this.beforeCallListener = beforeCallListener != null ? beforeCallListener : () -> { + }; + this.afterCallListener = afterCallListener != null ? afterCallListener : () -> { + }; + this.errListener = errListener != null ? errListener : () -> { + }; + } + + @Override + public void beforeCall(Object[] args, InstanceMethodCaller caller) { + callTracer.beforeCall(args, caller); + beforeCallListener.run(); + } + + @Override + public void afterCall(Object[] args, InstanceMethodCaller caller, Object result) { + callTracer.afterCall(args, caller, result); + afterCallListener.run(); + } + + @Override + public void callError(Object[] args, InstanceMethodCaller caller, Throwable error) { + callTracer.callError(args, caller, error); + errListener.run(); + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/MetadataTracer.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/MetadataTracer.java new file mode 100644 index 0000000..4576a0a --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/MetadataTracer.java @@ -0,0 +1,86 @@ +package com.rbkmoney.woody.api.trace.context; + +import com.rbkmoney.woody.api.event.ClientEventType; +import com.rbkmoney.woody.api.event.ServiceEventType; +import com.rbkmoney.woody.api.proxy.InstanceMethodCaller; +import com.rbkmoney.woody.api.proxy.MethodCallTracer; +import com.rbkmoney.woody.api.trace.Metadata; +import com.rbkmoney.woody.api.trace.MetadataProperties; + +/** + * Created by vpankrashkin on 25.04.16. + */ +public class MetadataTracer implements MethodCallTracer { + private final boolean isClient; + private final boolean isAuto; + + public static MetadataTracer forClient() { + return new MetadataTracer(true); + } + + public static MetadataTracer forServer() { + return new MetadataTracer(true); + } + + public static MetadataTracer forAuto() { + return new MetadataTracer(); + } + + public MetadataTracer() { + this.isAuto = true; + this.isClient = false; + } + + public MetadataTracer(boolean isClient) { + this.isAuto = false; + this.isClient = isClient; + } + + @Override + public void beforeCall(Object[] args, InstanceMethodCaller caller) { + boolean isClient = isClient(); + setBeforeCall(isClient ? + TraceContext.getCurrentTraceData().getClientSpan().getMetadata() : + TraceContext.getCurrentTraceData().getServerSpan().getMetadata(), + args, caller, isClient); + + } + + @Override + public void afterCall(Object[] args, InstanceMethodCaller caller, Object result) { + boolean isClient = isClient(); + setAfterCall(isClient ? + TraceContext.getCurrentTraceData().getClientSpan().getMetadata() : + TraceContext.getCurrentTraceData().getServerSpan().getMetadata(), + args, caller, result, isClient); + } + + @Override + public void callError(Object[] args, InstanceMethodCaller caller, Throwable error) { + boolean isClient = isClient(); + setCallError(isClient ? + TraceContext.getCurrentTraceData().getClientSpan().getMetadata() : + TraceContext.getCurrentTraceData().getServerSpan().getMetadata(), + args, caller, error, isClient); + } + + private void setBeforeCall(Metadata metadata, Object[] args, InstanceMethodCaller caller, boolean isClient) { + metadata.putValue(MetadataProperties.CALL_ARGUMENTS, args); + metadata.putValue(MetadataProperties.INSTANCE_METHOD_CALLER, caller); + metadata.putValue(MetadataProperties.EVENT_TYPE, isClient ? ClientEventType.CALL_SERVICE : ServiceEventType.CALL_HANDLER); + } + + private void setAfterCall(Metadata metadata, Object[] args, InstanceMethodCaller caller, Object result, boolean isClient) { + metadata.putValue(MetadataProperties.CALL_RESULT, result); + metadata.putValue(MetadataProperties.EVENT_TYPE, isClient ? ClientEventType.SERVICE_RESULT : ServiceEventType.HANDLER_RESULT); + } + + private void setCallError(Metadata metadata, Object[] args, InstanceMethodCaller caller, Throwable error, boolean isClient) { + metadata.putValue(MetadataProperties.CALL_ERROR, error); + metadata.putValue(MetadataProperties.EVENT_TYPE, isClient ? ClientEventType.ERROR : ServiceEventType.ERROR); + } + + private boolean isClient() { + return isAuto ? TraceContext.getCurrentTraceData().isClient() : isClient; + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/TraceContext.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/TraceContext.java new file mode 100644 index 0000000..ba84d6d --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/TraceContext.java @@ -0,0 +1,161 @@ +package com.rbkmoney.woody.api.trace.context; + +import com.rbkmoney.woody.api.generator.IdGenerator; +import com.rbkmoney.woody.api.trace.Span; +import com.rbkmoney.woody.api.trace.TraceData; + +import static com.rbkmoney.woody.api.generator.IdGenerator.NO_PARENT_ID; + +/** + * Created by vpankrashkin on 25.04.16. + */ +public class TraceContext { + private final static ThreadLocal currentTraceData = ThreadLocal.withInitial(() -> new TraceData()); + + public static TraceData getCurrentTraceData() { + return currentTraceData.get(); + } + + public static void setCurrentTraceData(TraceData traceData) { + if (traceData == null) { + currentTraceData.remove(); + } else { + currentTraceData.set(traceData); + } + } + + public static void reset() { + //accept the idea that limited set of objects (cleaned TraceData) will stay bound to thread after instance death + //currently will lead to memory leak if lots of TraceContext classloads (which means lots of static thread locals) occurs in same thread + TraceData traceData = getCurrentTraceData(); + if (traceData != null) { + traceData.reset(); + } + + } + + public static TraceContext forClient(IdGenerator idGenerator, Runnable postInit, Runnable preDestroy) { + return new TraceContext(idGenerator, postInit, preDestroy); + } + + public static TraceContext forServer(IdGenerator idGenerator, Runnable postInit, Runnable preDestroy) { + return new TraceContext(idGenerator, postInit, preDestroy); + } + + private final IdGenerator idGenerator; + private final Runnable postInit; + private final Runnable preDestroy; + private final boolean isAuto; + private final boolean isClient; + + public TraceContext(IdGenerator idGenerator) { + this(idGenerator, () -> { + }, () -> { + }); + } + + public TraceContext(IdGenerator idGenerator, Runnable postInit, Runnable preDestroy) { + this.idGenerator = idGenerator; + this.postInit = postInit; + this.preDestroy = preDestroy; + this.isAuto = true; + this.isClient = false; + } + + public TraceContext(IdGenerator idGenerator, Runnable postInit, Runnable preDestroy, boolean isClient) { + this.idGenerator = idGenerator; + this.postInit = postInit; + this.preDestroy = preDestroy; + this.isAuto = false; + this.isClient = isClient; + } + + /** + * Server span must be already read and set, mustn't be invoked if any transport problems occurred + */ + public void init() { + TraceData traceData = getCurrentTraceData(); + if (isClientInit(traceData)) { + initClientContext(traceData); + } else { + initServerContext(traceData); + } + postInit.run(); + } + + public void destroy() { + TraceData traceData = getCurrentTraceData(); + boolean isClient = isClientDestroy(traceData); + setDuration(isClient ? traceData.getClientSpan().getSpan() : traceData.getServerSpan().getSpan()); + try { + preDestroy.run(); + } finally { + if (isClient) { + destroyClientContext(traceData); + } else { + destroyServerContext(traceData); + } + } + } + + private void initClientContext(TraceData traceData) { + long timestamp = System.currentTimeMillis(); + Span clientSpan = traceData.getClientSpan().getSpan(); + Span serverSpan = traceData.getServerSpan().getSpan(); + + boolean root = traceData.isRoot(); + String traceId = root ? idGenerator.generateId(timestamp) : serverSpan.getTraceId(); + if (root) { + clientSpan.setId(traceId); + clientSpan.setParentId(NO_PARENT_ID); + } else { + clientSpan.setId(idGenerator.generateId(timestamp, traceData.getServerSpan().getCounter().incrementAndGet())); + clientSpan.setParentId(serverSpan.getId()); + } + clientSpan.setTraceId(traceId); + clientSpan.setTimestamp(timestamp); + } + + private void destroyClientContext(TraceData traceData) { + traceData.getClientSpan().reset(); + } + + private void initServerContext(TraceData traceData) { + long timestamp = System.currentTimeMillis(); + traceData.getServerSpan().getSpan().setTimestamp(timestamp); + } + + private void destroyServerContext(TraceData traceData) { + TraceContext.reset(); + } + + private void setDuration(Span span) { + span.setDuration(System.currentTimeMillis() - span.getTimestamp()); + } + + private boolean isClientInit(TraceData traceData) { + return isAuto ? isClientInitAuto(traceData) : isClient; + } + + private boolean isClientDestroy(TraceData traceData) { + return isAuto ? isClientDestroyAuto(traceData) : isClient; + } + + private boolean isClientInitAuto(TraceData traceData) { + Span serverSpan = traceData.getServerSpan().getSpan(); + + assert !(traceData.getClientSpan().isStarted() & traceData.getServerSpan().isStarted()); + assert !(traceData.getClientSpan().isFilled() & traceData.getServerSpan().isFilled()); + + return serverSpan.isFilled() ? serverSpan.isStarted() : true; + + } + + private boolean isClientDestroyAuto(TraceData traceData) { + assert !(traceData.getClientSpan().isStarted() || traceData.getServerSpan().isStarted()); + + return traceData.getServerSpan().isStarted() ? traceData.getClientSpan().isStarted() : true; + + } + +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientRequestInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientRequestInterceptor.java new file mode 100644 index 0000000..efa1ea7 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientRequestInterceptor.java @@ -0,0 +1,9 @@ +package com.rbkmoney.woody.api.transport.interceptor; + +import com.rbkmoney.woody.api.trace.ClientSpan; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public interface ClientRequestInterceptor extends RequestInterceptor { +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientResponseInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientResponseInterceptor.java new file mode 100644 index 0000000..194989e --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientResponseInterceptor.java @@ -0,0 +1,9 @@ +package com.rbkmoney.woody.api.transport.interceptor; + +import com.rbkmoney.woody.api.trace.ServerSpan; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public interface ClientResponseInterceptor extends ResponseInterceptor { +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/RequestInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/RequestInterceptor.java new file mode 100644 index 0000000..0d2cf3d --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/RequestInterceptor.java @@ -0,0 +1,10 @@ +package com.rbkmoney.woody.api.transport.interceptor; + +import com.rbkmoney.woody.api.trace.AbstractSpan; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public interface RequestInterceptor { + boolean interceptRequest(Context context, Transport spanContext); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ResponseInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ResponseInterceptor.java new file mode 100644 index 0000000..87edd0d --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ResponseInterceptor.java @@ -0,0 +1,10 @@ +package com.rbkmoney.woody.api.transport.interceptor; + +import com.rbkmoney.woody.api.trace.AbstractSpan; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public interface ResponseInterceptor { + void interceptResponse(Context context, Transport transport); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerRequestInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerRequestInterceptor.java new file mode 100644 index 0000000..bf3ce95 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerRequestInterceptor.java @@ -0,0 +1,9 @@ +package com.rbkmoney.woody.api.transport.interceptor; + +import com.rbkmoney.woody.api.trace.ServerSpan; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public interface ServerRequestInterceptor extends RequestInterceptor { +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerResponseIntercepor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerResponseIntercepor.java new file mode 100644 index 0000000..235c790 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerResponseIntercepor.java @@ -0,0 +1,9 @@ +package com.rbkmoney.woody.api.transport.interceptor; + +import com.rbkmoney.woody.api.trace.ServerSpan; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public interface ServerResponseIntercepor extends ResponseInterceptor { +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/WrappedRequestInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/WrappedRequestInterceptor.java new file mode 100644 index 0000000..547c41b --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/WrappedRequestInterceptor.java @@ -0,0 +1,36 @@ +package com.rbkmoney.woody.api.transport.interceptor; + +import com.rbkmoney.woody.api.event.ClientEventType; +import com.rbkmoney.woody.api.event.ServiceEventType; +import com.rbkmoney.woody.api.trace.AbstractSpan; +import com.rbkmoney.woody.api.trace.MetadataProperties; +import com.rbkmoney.woody.api.trace.TraceData; +import com.rbkmoney.woody.api.trace.context.TraceContext; + +/** + * Created by vpankrashkin on 27.04.16. + */ +public class WrappedRequestInterceptor implements RequestInterceptor { + private final RequestInterceptor interceptor; + private final Runnable listener; + + public WrappedRequestInterceptor(RequestInterceptor interceptor, Runnable listener) { + this.interceptor = interceptor; + this.listener = listener; + } + + @Override + public boolean interceptRequest(Context context, Transport spanContext) { + TraceData traceContext = TraceContext.getCurrentTraceData(); + boolean isClient = traceContext.isClient(); + + if (interceptor.interceptRequest(context, spanContext)) { + traceContext.getActiveSpan().getMetadata().putValue(MetadataProperties.EVENT_TYPE, isClient ? ClientEventType.CLIENT_RECEIVE : ServiceEventType.SERVICE_RECEIVE); + listener.run(); + return true; + } else { + traceContext.getActiveSpan().getMetadata().putValue(MetadataProperties.EVENT_TYPE, isClient ? ClientEventType.ERROR : ServiceEventType.ERROR); + return false; + } + } +} diff --git a/woody-api/src/test/java/com/rbkmoney/woody/api/proxy/TestProxyInvocationFactory.java b/woody-api/src/test/java/com/rbkmoney/woody/api/proxy/TestProxyInvocationFactory.java new file mode 100644 index 0000000..9eafef0 --- /dev/null +++ b/woody-api/src/test/java/com/rbkmoney/woody/api/proxy/TestProxyInvocationFactory.java @@ -0,0 +1,101 @@ +package com.rbkmoney.woody.api.proxy; + +import com.rbkmoney.woody.api.trace.context.EventListenerTracer; +import org.junit.Test; + +import static org.junit.Assert.assertSame; + +/** + * Created by vpankrashkin on 23.04.16. + */ +public class TestProxyInvocationFactory { + @Test + public void testString() { + //Srv direct = () -> "test"; + Srv directImpl = new Srv() { + + @Override + public String getString() { + return "string"; + } + }; + MethodCallTracer callTracer = new MethodCallTracer() { + @Override + public void beforeCall(Object[] args, InstanceMethodCaller caller) { + //System.out.println("Before"); + } + + @Override + public void afterCall(Object[] args, InstanceMethodCaller caller, Object result) { + //System.out.println("After"); + } + + @Override + public void callError(Object[] args, InstanceMethodCaller caller, Throwable error) { + //System.out.println("Error:" + error); + error.printStackTrace(); + } + }; + + MethodCallTracer wrappedCallTracer = new EventListenerTracer(callTracer); + + ProxyFactory reflectionProxyFactory = new ProxyFactory(new ReflectionMethodCallerFactory(), wrappedCallTracer, false); + ProxyFactory handleProxyFactory = new ProxyFactory(new HandleMethodCallerFactory(), wrappedCallTracer, false); + + Srv directLambda = () -> "string"; + Srv refDirectProxy = reflectionProxyFactory.getInstance(Srv.class, directImpl); + Srv refLambdaProxy = reflectionProxyFactory.getInstance(Srv.class, directLambda); + Srv handleDirectProxy = handleProxyFactory.getInstance(Srv.class, directImpl); + Srv handleLambdaProxy = handleProxyFactory.getInstance(Srv.class, directLambda); + handleDirectProxy.getString(); + handleLambdaProxy.getString(); + for (int i = 0; i < 1000000; i++) { + assertSame(directImpl.getString(), refDirectProxy.getString()); + assertSame(directImpl.getString(), refLambdaProxy.getString()); + assertSame(directImpl.getString(), handleDirectProxy.getString()); + assertSame(directImpl.getString(), handleLambdaProxy.getString()); + } + + long start = System.currentTimeMillis(); + for (int i = 0; i < 5000000; i++) { + directImpl.getString(); + } + System.out.println("Direct:" + (System.currentTimeMillis() - start)); + + start = System.currentTimeMillis(); + for (int i = 0; i < 5000000; i++) { + directLambda.getString(); + } + System.out.println("Lambda:" + (System.currentTimeMillis() - start)); + + start = System.currentTimeMillis(); + for (int i = 0; i < 5000000; i++) { + refDirectProxy.getString(); + } + System.out.println("Refl Direct roxy:" + (System.currentTimeMillis() - start)); + + start = System.currentTimeMillis(); + for (int i = 0; i < 5000000; i++) { + refLambdaProxy.getString(); + } + System.out.println("Refl Lambda roxy:" + (System.currentTimeMillis() - start)); + + + start = System.currentTimeMillis(); + for (int i = 0; i < 5000000; i++) { + handleDirectProxy.getString(); + } + System.out.println("Handle Direct Proxy:" + (System.currentTimeMillis() - start)); + + start = System.currentTimeMillis(); + for (int i = 0; i < 5000000; i++) { + handleLambdaProxy.getString(); + } + System.out.println("Handle Lambda Proxy:" + (System.currentTimeMillis() - start)); + + } + + private interface Srv { + String getString(); + } +} diff --git a/woody-thrift/pom.xml b/woody-thrift/pom.xml new file mode 100644 index 0000000..3d24008 --- /dev/null +++ b/woody-thrift/pom.xml @@ -0,0 +1,15 @@ + + + + woody + com.rbkmoney.woody + 1.0.0 + + 4.0.0 + + woody-thrift + + + \ No newline at end of file diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/ErrorCallType.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/ErrorCallType.java new file mode 100644 index 0000000..5d3112e --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/ErrorCallType.java @@ -0,0 +1,24 @@ +package com.rbkmoney.woody.thrift; + +/** + * Created by vpankrashkin on 22.04.16. + *

+ * Custom error call constants, specific for + */ +public enum ErrorCallType { + /** + * Any thrift errors (protocol, transport, etc). + */ + PROVIDER_ERROR, + + /** + * Error which is registered in service method declaration. + */ + APPLICATION_KNOWN_ERROR, + + /** + * Any other error which is not registered for calling method and doesn't refer to thrift errors. + */ + APPLICATION_UNKNOWN_ERROR + +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/TransportErrorType.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/TransportErrorType.java new file mode 100644 index 0000000..fa2e95d --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/TransportErrorType.java @@ -0,0 +1,11 @@ +package com.rbkmoney.woody.thrift.impl.http.transport; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public enum TransportErrorType { + NO_DATA, + BAD_REQUEST_TYPE, + BAD_CONTENT_TYPE + +} From d97847f4e4f8c3b14901173c45c034446f01b70c Mon Sep 17 00:00:00 2001 From: Vladimir Pankrashkin Date: Thu, 12 May 2016 00:58:03 +0300 Subject: [PATCH 2/5] MSPF-16: Client and server part --- README.md | 4 +- pom.xml | 3 + woody-api/pom.xml | 2 + .../woody/api/AbstractClientBuilder.java | 129 +++++++----- .../woody/api/AbstractServiceBuilder.java | 164 +++++++++++++++ .../com/rbkmoney/woody/api/ClientBuilder.java | 3 - .../rbkmoney/woody/api/ServiceBuilder.java | 11 +- .../woody/api/ServiceConfigurator.java | 8 - .../api/WoodyInstantiationException.java | 26 +++ .../rbkmoney/woody/api/event/CallType.java | 9 + .../rbkmoney/woody/api/event/ClientEvent.java | 19 ++ .../woody/api/event/ClientEventListener.java | 7 +- .../rbkmoney/woody/api/event/ErrorType.java | 25 ++- .../com/rbkmoney/woody/api/event/Event.java | 81 ++++++++ .../woody/api/event/EventListener.java | 8 +- .../woody/api/event/ServiceEvent.java | 18 ++ .../woody/api/event/ServiceEventListener.java | 8 +- .../interceptor/BasicCommonInterceptor.java | 27 +++ .../api/interceptor/CommonInterceptor.java | 7 + .../api/interceptor/CompositeInterceptor.java | 50 +++++ .../api/interceptor/ContextInterceptor.java | 34 ++++ .../interceptor/EmptyCommonInterceptor.java | 19 ++ .../api/interceptor/RequestInterceptor.java | 13 ++ .../api/interceptor/ResponseInterceptor.java | 13 ++ .../api/provider/ClientProviderControl.java | 8 - .../provider/ProviderEventInterceptor.java | 37 ++++ .../api/proxy/HandleMethodCallerFactory.java | 2 +- .../woody/api/proxy/InstanceMethodCaller.java | 18 +- .../woody/api/proxy/MethodCallTracer.java | 1 + .../proxy/ReflectionMethodCallerFactory.java | 12 +- .../rbkmoney/woody/api/trace/ClientSpan.java | 2 +- .../{AbstractSpan.java => ContextSpan.java} | 2 +- .../woody/api/trace/ContextUtils.java | 64 ++++++ .../rbkmoney/woody/api/trace/Endpoint.java | 6 +- .../rbkmoney/woody/api/trace/Metadata.java | 4 + .../woody/api/trace/MetadataProperties.java | 14 +- .../{ServerSpan.java => ServiceSpan.java} | 13 +- .../rbkmoney/woody/api/trace/TraceData.java | 24 +-- .../api/trace/context/CompositeTracer.java | 43 ++++ .../api/trace/context/ContextTracer.java | 4 +- .../woody/api/trace/context/EmptyTracer.java | 24 +++ ...ntListenerTracer.java => EventTracer.java} | 16 +- .../api/trace/context/MetadataTracer.java | 16 +- .../woody/api/trace/context/TraceContext.java | 49 +++-- .../transport/TransportEventInterceptor.java | 37 ++++ .../interceptor/ClientRequestInterceptor.java | 9 - .../ClientResponseInterceptor.java | 9 - .../interceptor/RequestInterceptor.java | 10 - .../interceptor/ResponseInterceptor.java | 10 - .../interceptor/ServerRequestInterceptor.java | 9 - .../interceptor/ServerResponseIntercepor.java | 9 - .../WrappedRequestInterceptor.java | 36 ---- .../api/proxy/TestProxyInvocationFactory.java | 4 +- woody-thrift/pom.xml | 65 ++++++ .../rbkmoney/woody/thrift/ErrorCallType.java | 24 --- .../woody/thrift/impl/http/TErrorType.java | 11 + .../thrift/impl/http/THClientBuilder.java | 149 ++++++++++++++ .../impl/http/THErrorMetadataExtender.java | 190 ++++++++++++++++++ .../impl/http/THMetadataProperties.java | 22 ++ .../thrift/impl/http/THSProtocolWrapper.java | 42 ++++ .../thrift/impl/http/THServiceBuilder.java | 153 ++++++++++++++ .../thrift/impl/http/event/THClientEvent.java | 35 ++++ .../impl/http/event/THServiceEvent.java | 35 ++++ .../THCEventCommonInterceptorDEL.java | 33 +++ .../THCMessageRequestInterceptor.java | 36 ++++ .../THCMessageResponseInterceptor.java | 31 +++ .../interceptor/THCRequestInterceptor.java | 64 ++++++ .../interceptor/THCResponseInterceptor.java | 48 +++++ .../THRequestInterceptionException.java | 19 ++ .../THSMessageRequestInterceptor.java | 36 ++++ .../THSMessageResponseInterceptor.java | 31 +++ .../interceptor/THSRequestInterceptor.java | 81 ++++++++ .../interceptor/THSResponseInterceptor.java | 146 ++++++++++++++ .../THSResponseMetadataInterceptor.java | 24 +++ .../impl/http/transport/THttpHeader.java | 22 ++ .../http/transport/TTransportErrorType.java | 11 + .../http/transport/TransportErrorType.java | 11 - .../http/transport/UrlStringEndpoint.java | 24 +++ .../rbkmoney/woody/rpc/OwnerServiceImpl.java | 33 +++ .../java/com/rbkmoney/woody/rpc/TestHttp.java | 72 +++++++ .../com/rbkmoney/woody/rpc/TestSocket.java | 88 ++++++++ .../thrift/impl/http/AbstractClientTest.java | 96 +++++++++ .../thrift/impl/http/IdGeneratorStub.java | 18 ++ .../thrift/impl/http/OwnerServiceStub.java | 36 ++++ .../impl/http/TestClientErrHandling.java | 176 ++++++++++++++++ .../impl/http/TestErrLoadThriftRPCClient.java | 164 +++++++++++++++ .../impl/http/TestLoadThriftRPCClient.java | 169 ++++++++++++++++ .../test/resources/jetty-logging.properties | 6 + .../src/test/thrift/testService.thrift | 20 ++ 89 files changed, 3106 insertions(+), 295 deletions(-) create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/AbstractServiceBuilder.java delete mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/ServiceConfigurator.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/WoodyInstantiationException.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/event/CallType.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEvent.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/event/Event.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEvent.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/BasicCommonInterceptor.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/CommonInterceptor.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/CompositeInterceptor.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/ContextInterceptor.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/EmptyCommonInterceptor.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/RequestInterceptor.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/ResponseInterceptor.java delete mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/provider/ClientProviderControl.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/provider/ProviderEventInterceptor.java rename woody-api/src/main/java/com/rbkmoney/woody/api/trace/{AbstractSpan.java => ContextSpan.java} (95%) create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/trace/ContextUtils.java rename woody-api/src/main/java/com/rbkmoney/woody/api/trace/{ServerSpan.java => ServiceSpan.java} (57%) create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/CompositeTracer.java create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/EmptyTracer.java rename woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/{EventListenerTracer.java => EventTracer.java} (61%) create mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/transport/TransportEventInterceptor.java delete mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientRequestInterceptor.java delete mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientResponseInterceptor.java delete mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/RequestInterceptor.java delete mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ResponseInterceptor.java delete mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerRequestInterceptor.java delete mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerResponseIntercepor.java delete mode 100644 woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/WrappedRequestInterceptor.java delete mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/ErrorCallType.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/TErrorType.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THClientBuilder.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THErrorMetadataExtender.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THMetadataProperties.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THSProtocolWrapper.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THServiceBuilder.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/THClientEvent.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/THServiceEvent.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCEventCommonInterceptorDEL.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCMessageRequestInterceptor.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCMessageResponseInterceptor.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCRequestInterceptor.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCResponseInterceptor.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THRequestInterceptionException.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSMessageRequestInterceptor.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSMessageResponseInterceptor.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSRequestInterceptor.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSResponseInterceptor.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSResponseMetadataInterceptor.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/THttpHeader.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/TTransportErrorType.java delete mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/TransportErrorType.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/UrlStringEndpoint.java create mode 100644 woody-thrift/src/test/java/com/rbkmoney/woody/rpc/OwnerServiceImpl.java create mode 100644 woody-thrift/src/test/java/com/rbkmoney/woody/rpc/TestHttp.java create mode 100644 woody-thrift/src/test/java/com/rbkmoney/woody/rpc/TestSocket.java create mode 100644 woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/AbstractClientTest.java create mode 100644 woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/IdGeneratorStub.java create mode 100644 woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/OwnerServiceStub.java create mode 100644 woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestClientErrHandling.java create mode 100644 woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestErrLoadThriftRPCClient.java create mode 100644 woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestLoadThriftRPCClient.java create mode 100644 woody-thrift/src/test/resources/jetty-logging.properties create mode 100644 woody-thrift/src/test/thrift/testService.thrift diff --git a/README.md b/README.md index 9ee7fbd..5f0a1ef 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# rpc +# com.rbkmoney.woody.rpc -Java реализация [Библиотеки RPC вызовов для общения между микросервисами](http://52.29.202.218/scrapyard/rpc-lib/). +Java реализация [Библиотеки RPC вызовов для общения между микросервисами](http://52.29.202.218/scrapyard/com.rbkmoney.woody.rpc-lib/). diff --git a/pom.xml b/pom.xml index 577bfec..ce67b99 100644 --- a/pom.xml +++ b/pom.xml @@ -8,6 +8,9 @@ woody 1.0.0 Java implementation for Woody spec + + 1.0.0 + woody-api diff --git a/woody-api/pom.xml b/woody-api/pom.xml index f84b514..8fc2e7b 100644 --- a/woody-api/pom.xml +++ b/woody-api/pom.xml @@ -10,6 +10,8 @@ 4.0.0 woody-api + ${api-version} + jar diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/AbstractClientBuilder.java b/woody-api/src/main/java/com/rbkmoney/woody/api/AbstractClientBuilder.java index 7769b14..932de12 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/AbstractClientBuilder.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/AbstractClientBuilder.java @@ -2,13 +2,9 @@ package com.rbkmoney.woody.api; import com.rbkmoney.woody.api.event.ClientEventListener; import com.rbkmoney.woody.api.generator.IdGenerator; -import com.rbkmoney.woody.api.provider.ClientProviderControl; import com.rbkmoney.woody.api.proxy.MethodCallTracer; import com.rbkmoney.woody.api.proxy.ProxyFactory; -import com.rbkmoney.woody.api.trace.context.ContextTracer; -import com.rbkmoney.woody.api.trace.context.EventListenerTracer; -import com.rbkmoney.woody.api.trace.context.MetadataTracer; -import com.rbkmoney.woody.api.trace.context.TraceContext; +import com.rbkmoney.woody.api.trace.context.*; import java.net.URI; @@ -38,53 +34,78 @@ public abstract class AbstractClientBuilder implements ClientBuilder { return this; } - @Override - public T build(Class clientInterface) { - return createProxyClient(clientInterface, null); + protected URI getAddress() { + return address; + } + + protected ClientEventListener getEventListener() { + return eventListener; + } + + protected IdGenerator getIdGenerator() { + return idGenerator; } @Override - public T build(Class clientInterface, ClientProviderControl providerControl) { - T target = null; - return createProxyClient(clientInterface, target); + public T build(Class clientInterface) { + try { + T target = createProviderClient(clientInterface); + return createProxyClient(clientInterface, target); + } catch (Exception e) { + throw new WoodyInstantiationException(e); + } } protected T createProxyClient(Class clientInterface, T target) { - ProxyBuilder proxyBuilder = new ProxyBuilder(); - proxyBuilder.setIdGenerator(idGenerator); - proxyBuilder.setStartEventListener(getEventStartListener(eventListener)); - proxyBuilder.setEndEventListener(getEventEndListener(eventListener)); - proxyBuilder.setErrEventListener(getErrorListener(eventListener)); - proxyBuilder.setStartEventPhases(ProxyBuilder.BEFORE_CALL_START); - proxyBuilder.setEndEventPhases(ProxyBuilder.BEFORE_CONTEXT_DESTROY); - return proxyBuilder.build(clientInterface, target); - + return createProxyBuilder(clientInterface).build(clientInterface, target); } - abstract protected Runnable getErrorListener(ClientEventListener eventListener); + protected ProxyBuilder createProxyBuilder(Class clientInterface) { + ProxyBuilder proxyBuilder = new ProxyBuilder(); + proxyBuilder.setIdGenerator(idGenerator); + proxyBuilder.setStartEventListener(getOnCallStartEventListener()); + proxyBuilder.setEndEventListener(getOnCallEndEventListener()); + proxyBuilder.setErrEventListener(getErrorListener()); + proxyBuilder.setMetadataExtender(getOnCallMetadataExtender(clientInterface)); + return proxyBuilder; + } - abstract protected Runnable getEventStartListener(ClientEventListener eventListener); + abstract protected Runnable getErrorListener(); - abstract protected Runnable getEventEndListener(ClientEventListener eventListener); + abstract protected Runnable getOnCallStartEventListener(); - abstract T createProxyTarget(Class clientInterface, ClientEventListener listener, ClientProviderControl providerControl); + abstract protected Runnable getOnSendEventListener(); + + abstract protected Runnable getOnReceiveEventListener(); + + abstract protected Runnable getOnCallEndEventListener(); + + abstract protected MethodCallTracer getOnCallMetadataExtender(Class clientInterface); + + abstract protected T createProviderClient(Class clientInterface); protected static class ProxyBuilder { - private static final int AFTER_CONTEXT_INIT = 0b01; - private static final int BEFORE_CONTEXT_DESTROY = 0b10; - private static final int BEFORE_CALL_START = 0b100; - private static final int AFTER_CALL_END = 0b1000; + public static final int EVENT_DISABLE = 0b0; + public static final int EVENT_AFTER_CONTEXT_INIT = 0b01; + public static final int EVENT_BEFORE_CONTEXT_DESTROY = 0b10; + public static final int EVENT_BEFORE_CALL_START = 0b100; + public static final int EVENT_AFTER_CALL_END = 0b1000; private int startEventPhases; private int endEventPhases; + private int errorEventPhases; private boolean allowObjectOverriding = false; - private final Runnable stub = () -> { + private final Runnable listenerStub = () -> { }; + + private final MethodCallTracer extenderStub = new EmptyTracer(); + private Runnable startEventListener; private Runnable endEventListener; private Runnable errEventListener; private IdGenerator idGenerator; + private MethodCallTracer metadataExtender; public void setStartEventListener(Runnable startEventListener) { this.startEventListener = startEventListener; @@ -102,6 +123,10 @@ public abstract class AbstractClientBuilder implements ClientBuilder { this.idGenerator = idGenerator; } + public void setMetadataExtender(MethodCallTracer metadataExtender) { + this.metadataExtender = metadataExtender; + } + public void setAllowObjectOverriding(boolean allowObjectOverriding) { this.allowObjectOverriding = allowObjectOverriding; } @@ -114,25 +139,8 @@ public abstract class AbstractClientBuilder implements ClientBuilder { endEventPhases = phases; } - public ProxyFactory createProxyFactory() { - return new ProxyFactory(createMethodCallTracer(), allowObjectOverriding); - } - - public MethodCallTracer createMethodCallTracer() { - return new ContextTracer(createTraceContext(), createEventTracer()); - } - - public TraceContext createTraceContext() { - return TraceContext.forClient(idGenerator, - hasFlag(AFTER_CONTEXT_INIT, startEventPhases) ? startEventListener : stub, - hasFlag(BEFORE_CONTEXT_DESTROY, endEventPhases) ? endEventListener : startEventListener); - } - - public EventListenerTracer createEventTracer() { - return new EventListenerTracer(MetadataTracer.forClient(), - hasFlag(BEFORE_CALL_START, startEventPhases) ? startEventListener : stub, - hasFlag(AFTER_CALL_END, endEventPhases) ? endEventListener : stub, - errEventListener); + public void setErrorEventPhases(int phases) { + this.errorEventPhases = phases; } public T build(Class clientInterface, T target) { @@ -140,6 +148,31 @@ public abstract class AbstractClientBuilder implements ClientBuilder { return proxyFactory.getInstance(clientInterface, target); } + protected ProxyFactory createProxyFactory() { + return new ProxyFactory(createMethodCallTracer(), allowObjectOverriding); + } + + protected MethodCallTracer createMethodCallTracer() { + return new ContextTracer(createTraceContext(), createEventTracer()); + } + + protected TraceContext createTraceContext() { + return TraceContext.forClient(idGenerator, + hasFlag(EVENT_AFTER_CONTEXT_INIT, startEventPhases) ? startEventListener : listenerStub, + hasFlag(EVENT_BEFORE_CONTEXT_DESTROY, endEventPhases) ? endEventListener : listenerStub, + hasFlag(EVENT_BEFORE_CONTEXT_DESTROY, errorEventPhases) ? errEventListener : listenerStub); + } + + protected MethodCallTracer createEventTracer() { + return new CompositeTracer(MetadataTracer.forClient(), + metadataExtender == null ? extenderStub : metadataExtender, + new EventTracer( + hasFlag(EVENT_BEFORE_CALL_START, startEventPhases) ? startEventListener : listenerStub, + hasFlag(EVENT_AFTER_CALL_END, endEventPhases) ? endEventListener : listenerStub, + errEventListener) + ); + } + private boolean hasFlag(int test, int flags) { return (test & flags) != 0; } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/AbstractServiceBuilder.java b/woody-api/src/main/java/com/rbkmoney/woody/api/AbstractServiceBuilder.java new file mode 100644 index 0000000..7d5414b --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/AbstractServiceBuilder.java @@ -0,0 +1,164 @@ +package com.rbkmoney.woody.api; + +import com.rbkmoney.woody.api.event.ServiceEventListener; +import com.rbkmoney.woody.api.generator.IdGenerator; +import com.rbkmoney.woody.api.proxy.MethodCallTracer; +import com.rbkmoney.woody.api.proxy.ProxyFactory; +import com.rbkmoney.woody.api.trace.context.CompositeTracer; +import com.rbkmoney.woody.api.trace.context.EmptyTracer; +import com.rbkmoney.woody.api.trace.context.EventTracer; +import com.rbkmoney.woody.api.trace.context.MetadataTracer; + +/** + * Created by vpankrashkin on 10.05.16. + */ +public abstract class AbstractServiceBuilder implements ServiceBuilder { + private ServiceEventListener eventListener; + private IdGenerator idGenerator; + + + @Override + public ServiceBuilder withEventListener(ServiceEventListener listener) { + this.eventListener = listener; + return this; + } + + @Override + public ServiceBuilder withIdGenerator(IdGenerator generator) { + this.idGenerator = generator; + return this; + } + + protected IdGenerator getIdGenerator() { + return idGenerator; + } + + @Override + public Service build(Class serviceInterface, T serviceHandler) { + try { + T target = createProxyService(serviceInterface, serviceHandler); + return createProviderService(serviceInterface, target); + } catch (Exception e) { + throw new WoodyInstantiationException(e); + } + } + + protected ServiceEventListener getEventListener() { + return eventListener; + } + + abstract protected Runnable getErrorListener(); + + abstract protected Runnable getOnCallStartEventListener(); + + abstract protected Runnable getOnSendEventListener(); + + abstract protected Runnable getOnReceiveEventListener(); + + abstract protected Runnable getOnCallEndEventListener(); + + abstract protected MethodCallTracer getOnCallMetadataExtender(Class serviceInterface); + + abstract protected Service createProviderService(Class serviceInterface, T handler); + + + protected T createProxyService(Class serviceInterface, T handler) { + return createProxyBuilder(serviceInterface).build(serviceInterface, handler); + } + + protected ProxyBuilder createProxyBuilder(Class serviceInterface) { + ProxyBuilder proxyBuilder = new ProxyBuilder(); + proxyBuilder.setIdGenerator(idGenerator); + proxyBuilder.setStartEventListener(getOnCallStartEventListener()); + proxyBuilder.setEndEventListener(getOnCallEndEventListener()); + proxyBuilder.setErrEventListener(getErrorListener()); + proxyBuilder.setMetadataExtender(getOnCallMetadataExtender(serviceInterface)); + return proxyBuilder; + } + + protected static class ProxyBuilder { + public static final int EVENT_DISABLE = 0b0; + public static final int EVENT_BEFORE_CALL_START = 0b100; + public static final int EVENT_AFTER_CALL_END = 0b1000; + + private int startEventPhases; + private int endEventPhases; + private int errorEventPhases; + private boolean allowObjectOverriding = false; + + private final Runnable listenerStub = () -> { + }; + + private final MethodCallTracer extenderStub = new EmptyTracer(); + + private Runnable startEventListener; + private Runnable endEventListener; + private Runnable errEventListener; + private IdGenerator idGenerator; + private MethodCallTracer metadataExtender; + + public void setStartEventListener(Runnable startEventListener) { + this.startEventListener = startEventListener; + } + + public void setEndEventListener(Runnable endEventListener) { + this.endEventListener = endEventListener; + } + + public void setErrEventListener(Runnable errEventListener) { + this.errEventListener = errEventListener; + } + + public void setIdGenerator(IdGenerator idGenerator) { + this.idGenerator = idGenerator; + } + + public void setMetadataExtender(MethodCallTracer metadataExtender) { + this.metadataExtender = metadataExtender; + } + + public void setAllowObjectOverriding(boolean allowObjectOverriding) { + this.allowObjectOverriding = allowObjectOverriding; + } + + public void setStartEventPhases(int phases) { + startEventPhases = phases; + } + + public void setEndEventPhases(int phases) { + endEventPhases = phases; + } + + public void setErrorEventPhases(int phases) { + this.errorEventPhases = phases; + } + + public T build(Class serviceInterface, T target) { + ProxyFactory proxyFactory = createProxyFactory(); + return proxyFactory.getInstance(serviceInterface, target); + } + + protected ProxyFactory createProxyFactory() { + return new ProxyFactory(createMethodCallTracer(), allowObjectOverriding); + } + + protected MethodCallTracer createMethodCallTracer() { + return createEventTracer(); + } + + protected MethodCallTracer createEventTracer() { + return new CompositeTracer(MetadataTracer.forServer(), + metadataExtender == null ? extenderStub : metadataExtender, + new EventTracer( + hasFlag(EVENT_BEFORE_CALL_START, startEventPhases) ? startEventListener : listenerStub, + hasFlag(EVENT_AFTER_CALL_END, endEventPhases) ? endEventListener : listenerStub, + errEventListener) + ); + } + + private boolean hasFlag(int test, int flags) { + return (test & flags) != 0; + } + } + +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/ClientBuilder.java b/woody-api/src/main/java/com/rbkmoney/woody/api/ClientBuilder.java index dfcb0c2..a589f2e 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/ClientBuilder.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/ClientBuilder.java @@ -2,7 +2,6 @@ package com.rbkmoney.woody.api; import com.rbkmoney.woody.api.event.ClientEventListener; import com.rbkmoney.woody.api.generator.IdGenerator; -import com.rbkmoney.woody.api.provider.ClientProviderControl; import java.net.URI; @@ -17,6 +16,4 @@ public interface ClientBuilder { ClientBuilder withIdGenerator(IdGenerator generator); T build(Class clientInterface); - - T build(Class clientInterface, ClientProviderControl configurator); } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/ServiceBuilder.java b/woody-api/src/main/java/com/rbkmoney/woody/api/ServiceBuilder.java index 1557635..62399a8 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/ServiceBuilder.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/ServiceBuilder.java @@ -1,18 +1,15 @@ package com.rbkmoney.woody.api; +import com.rbkmoney.woody.api.event.ServiceEventListener; import com.rbkmoney.woody.api.generator.IdGenerator; -import java.beans.EventHandler; - /** * Created by vpankrashkin on 22.04.16. */ -public interface ServiceBuilder { - ServiceBuilder withEventHandler(EventHandler handler); +public interface ServiceBuilder { + ServiceBuilder withEventListener(ServiceEventListener listener); ServiceBuilder withIdGenerator(IdGenerator generator); - T build(Class serviceInterface); - - T build(Class serviceInterface, ServiceConfigurator configurator); + Service build(Class serviceInterface, T serviceHandler); } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/ServiceConfigurator.java b/woody-api/src/main/java/com/rbkmoney/woody/api/ServiceConfigurator.java deleted file mode 100644 index 920bc63..0000000 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/ServiceConfigurator.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.rbkmoney.woody.api; - -/** - * Created by vpankrashkin on 22.04.16. - */ -public interface ServiceConfigurator { - void configure(T serviceProvider); -} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/WoodyInstantiationException.java b/woody-api/src/main/java/com/rbkmoney/woody/api/WoodyInstantiationException.java new file mode 100644 index 0000000..eb4b224 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/WoodyInstantiationException.java @@ -0,0 +1,26 @@ +package com.rbkmoney.woody.api; + +/** + * Created by vpankrashkin on 05.05.16. + */ +public class WoodyInstantiationException extends RuntimeException { + public WoodyInstantiationException() { + super(); + } + + public WoodyInstantiationException(String message) { + super(message); + } + + public WoodyInstantiationException(String message, Throwable cause) { + super(message, cause); + } + + public WoodyInstantiationException(Throwable cause) { + super(cause); + } + + protected WoodyInstantiationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/CallType.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/CallType.java new file mode 100644 index 0000000..abf19d9 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/CallType.java @@ -0,0 +1,9 @@ +package com.rbkmoney.woody.api.event; + +/** + * Created by vpankrashkin on 05.05.16. + */ +public enum CallType { + CALL, + CAST +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEvent.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEvent.java new file mode 100644 index 0000000..436f96a --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEvent.java @@ -0,0 +1,19 @@ +package com.rbkmoney.woody.api.event; + +import com.rbkmoney.woody.api.trace.ContextSpan; +import com.rbkmoney.woody.api.trace.TraceData; + +/** + * Created by vpankrashkin on 06.05.16. + */ +public class ClientEvent extends Event { + + public ClientEvent(TraceData traceData) { + super(traceData); + } + + @Override + public ContextSpan getActiveSpan() { + return getTraceData().getClientSpan(); + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEventListener.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEventListener.java index e1a73be..f9e32be 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEventListener.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEventListener.java @@ -1,12 +1,9 @@ package com.rbkmoney.woody.api.event; -import com.rbkmoney.woody.api.trace.TraceData; - /** * Created by vpankrashkin on 22.04.16. */ -public interface ClientEventListener extends EventListener { - void notifyEvent(ClientEventType eventType, TraceData traceData); +public interface ClientEventListener extends EventListener { + void notifyEvent(ClientEvent event); - void notifyError(ErrorType errorType, TraceData traceData); } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ErrorType.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ErrorType.java index 7b1c548..05669f8 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ErrorType.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ErrorType.java @@ -2,9 +2,28 @@ package com.rbkmoney.woody.api.event; /** * Created by vpankrashkin on 22.04.16. + *

+ * Custom error call constants, specific for */ public enum ErrorType { - UNKNOWN_CALL, - TRANSPORT, - ERROR_CALL + /** + * Any thrift errors (protocol, transport, etc). + */ + PROVIDER_ERROR, + + /** + * Error which is registered in service method declaration. + */ + APPLICATION_KNOWN_ERROR, + + /** + * Any other error which is not registered for calling method and doesn't refer to thrift errors. + */ + APPLICATION_UNKNOWN_ERROR, + + /** + * Any other error + */ + OTHER + } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/Event.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/Event.java new file mode 100644 index 0000000..76ff158 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/Event.java @@ -0,0 +1,81 @@ +package com.rbkmoney.woody.api.event; + +import com.rbkmoney.woody.api.trace.*; + +/** + * Created by vpankrashkin on 06.05.16. + */ +public abstract class Event { + private final TraceData traceData; + + public Event(TraceData traceData) { + this.traceData = traceData; + } + + public TraceData getTraceData() { + return traceData; + } + + public ClientEventType getEventType() { + return getActiveSpan().getMetadata().getValue(MetadataProperties.EVENT_TYPE); + } + + public CallType getCallType() { + return getActiveSpan().getMetadata().getValue(MetadataProperties.CALL_TYPE); + } + + public String getCallName() { + return getActiveSpan().getMetadata().getValue(MetadataProperties.CALL_NAME); + } + + public Object[] getCallArguments() { + return getActiveSpan().getMetadata().getValue(MetadataProperties.CALL_ARGUMENTS); + } + + public Object getCallResult() { + return getActiveSpan().getMetadata().getValue(MetadataProperties.CALL_RESULT); + } + + public ErrorType getErrorType() { + return getActiveSpan().getMetadata().getValue(MetadataProperties.ERROR_TYPE); + } + + public String getErrorName() { + return getActiveSpan().getMetadata().getValue(MetadataProperties.ERROR_NAME); + } + + public String getErrorMessage() { + return getActiveSpan().getMetadata().getValue(MetadataProperties.ERROR_MESSAGE); + } + + public String getSpanId() { + return getActiveSpan().getSpan().getId(); + } + + public String getParentId() { + return getActiveSpan().getSpan().getParentId(); + } + + public String getTraceId() { + return getActiveSpan().getSpan().getTraceId(); + } + + public long getTimeStamp() { + return getActiveSpan().getSpan().getTimestamp(); + } + + public long getDuration() { + return getActiveSpan().getSpan().getDuration(); + } + + public Endpoint getEndpoint() { + return getActiveSpan().getMetadata().getValue(MetadataProperties.CALL_ENDPOINT); + } + + public boolean isSuccessfullCall() { + return !ContextUtils.hasCallErrors(getActiveSpan()); + + } + + public abstract ContextSpan getActiveSpan(); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/EventListener.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/EventListener.java index 7983d34..68fb91a 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/event/EventListener.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/EventListener.java @@ -1,12 +1,8 @@ package com.rbkmoney.woody.api.event; -import com.rbkmoney.woody.api.trace.TraceData; - /** * Created by vpankrashkin on 25.04.16. */ -public interface EventListener { - void notifyEvent(EvnT eventType, TraceData traceData); - - void notifyError(ErrT errorType, TraceData traceData); +public interface EventListener { + void notifyEvent(E event); } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEvent.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEvent.java new file mode 100644 index 0000000..7764d10 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEvent.java @@ -0,0 +1,18 @@ +package com.rbkmoney.woody.api.event; + +import com.rbkmoney.woody.api.trace.ContextSpan; +import com.rbkmoney.woody.api.trace.TraceData; + +/** + * Created by vpankrashkin on 06.05.16. + */ +public class ServiceEvent extends Event { + public ServiceEvent(TraceData traceData) { + super(traceData); + } + + @Override + public ContextSpan getActiveSpan() { + return getTraceData().getServiceSpan(); + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventListener.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventListener.java index 50bdac3..423e507 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventListener.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventListener.java @@ -1,12 +1,8 @@ package com.rbkmoney.woody.api.event; -import com.rbkmoney.woody.api.trace.TraceData; - /** * Created by vpankrashkin on 25.04.16. */ -public interface ServiceEventListener extends EventListener { - void notifyEvent(ServiceEventType eventType, TraceData traceData); - - void notifyError(ErrorType errorType, TraceData traceData); +public interface ServiceEventListener extends EventListener { + void notifyEvent(ServiceEvent serviceEvent); } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/BasicCommonInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/BasicCommonInterceptor.java new file mode 100644 index 0000000..9e16679 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/BasicCommonInterceptor.java @@ -0,0 +1,27 @@ +package com.rbkmoney.woody.api.interceptor; + +import com.rbkmoney.woody.api.trace.TraceData; + +/** + * Created by vpankrashkin on 04.05.16. + */ +public class BasicCommonInterceptor implements CommonInterceptor { + private RequestInterceptor requestInterceptor; + private ResponseInterceptor responseInterceptor; + + public BasicCommonInterceptor(RequestInterceptor requestInterceptor, ResponseInterceptor responseInterceptor) { + this.requestInterceptor = requestInterceptor == null ? new EmptyCommonInterceptor() : requestInterceptor; + this.responseInterceptor = responseInterceptor == null ? new EmptyCommonInterceptor() : responseInterceptor; + } + + @Override + public boolean interceptRequest(TraceData traceData, ReqProvider providerContext, Object... contextParams) { + return requestInterceptor.interceptRequest(traceData, providerContext, contextParams); + } + + @Override + public boolean interceptResponse(TraceData traceData, RespProvider providerContext, Object... contextParams) { + return responseInterceptor.interceptResponse(traceData, providerContext, contextParams); + } + +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/CommonInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/CommonInterceptor.java new file mode 100644 index 0000000..ec5b838 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/CommonInterceptor.java @@ -0,0 +1,7 @@ +package com.rbkmoney.woody.api.interceptor; + +/** + * Created by vpankrashkin on 28.04.16. + */ +public interface CommonInterceptor extends RequestInterceptor, ResponseInterceptor { +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/CompositeInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/CompositeInterceptor.java new file mode 100644 index 0000000..1f7a72e --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/CompositeInterceptor.java @@ -0,0 +1,50 @@ +package com.rbkmoney.woody.api.interceptor; + +import com.rbkmoney.woody.api.trace.TraceData; + +/** + * Created by vpankrashkin on 28.04.16. + */ +public class CompositeInterceptor implements CommonInterceptor { + private final CommonInterceptor[] interceptors; + private final boolean breakOnError; + + public CompositeInterceptor(boolean breakOnError, CommonInterceptor... interceptors) { + this.breakOnError = breakOnError; + this.interceptors = interceptors.clone(); + } + + public CompositeInterceptor(CommonInterceptor... interceptors) { + this(true, interceptors); + } + + /*public CompositeInterceptor(Collection interceptors) { + this(true, interceptors.stream().toArray(CommonInterceptor[]::new)); + }*/ + + @Override + public boolean interceptRequest(TraceData traceData, ReqProvider providerContext, Object... contextParams) { + boolean successful = true; + for (int i = 0; i < interceptors.length; ++i) { + successful &= interceptors[i].interceptRequest(traceData, providerContext, contextParams); + if (!successful && breakOnError) { + return false; + } + } + return successful; + } + + @Override + public boolean interceptResponse(TraceData traceData, RespProvider providerContext, Object... contextParams) { + boolean successful = true; + for (int i = 0; i < interceptors.length; ++i) { + successful &= interceptors[i].interceptResponse(traceData, providerContext, contextParams); + if (!successful && breakOnError) { + return false; + } + } + return true; + } + + +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/ContextInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/ContextInterceptor.java new file mode 100644 index 0000000..4c50254 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/ContextInterceptor.java @@ -0,0 +1,34 @@ +package com.rbkmoney.woody.api.interceptor; + +import com.rbkmoney.woody.api.trace.ContextUtils; +import com.rbkmoney.woody.api.trace.TraceData; +import com.rbkmoney.woody.api.trace.context.TraceContext; + +/** + * Created by vpankrashkin on 10.05.16. + */ +public class ContextInterceptor implements CommonInterceptor { + private final TraceContext traceContext; + private final CommonInterceptor interceptor; + + public ContextInterceptor(TraceContext traceContext, CommonInterceptor interceptor) { + this.traceContext = traceContext; + this.interceptor = interceptor; + } + + @Override + public boolean interceptRequest(TraceData traceData, ReqProvider providerContext, Object... contextParams) { + traceContext.init(); + return interceptor.interceptRequest(traceData, providerContext, contextParams); + } + + @Override + public boolean interceptResponse(TraceData traceData, RespProvider providerContext, Object... contextParams) { + try { + interceptor.interceptResponse(traceData, providerContext, contextParams); + } finally { + traceContext.destroy(ContextUtils.hasCallErrors(traceData.getActiveSpan())); + } + return false; + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/EmptyCommonInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/EmptyCommonInterceptor.java new file mode 100644 index 0000000..b36596e --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/EmptyCommonInterceptor.java @@ -0,0 +1,19 @@ +package com.rbkmoney.woody.api.interceptor; + +import com.rbkmoney.woody.api.trace.TraceData; + +/** + * Created by vpankrashkin on 05.05.16. + */ +public class EmptyCommonInterceptor implements CommonInterceptor { + + @Override + public boolean interceptRequest(TraceData traceData, ReqProvider providerContext, Object... contextParams) { + return true; + } + + @Override + public boolean interceptResponse(TraceData traceData, RespProvider providerContext, Object... contextParams) { + return true; + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/RequestInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/RequestInterceptor.java new file mode 100644 index 0000000..5c8b0f1 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/RequestInterceptor.java @@ -0,0 +1,13 @@ +package com.rbkmoney.woody.api.interceptor; + +import com.rbkmoney.woody.api.trace.TraceData; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public interface RequestInterceptor { + /** + * @return true - if request is successfully intercepted and ready for further processing; false - if interception failed and processing must be switched to request err handling + */ + boolean interceptRequest(TraceData traceData, Provider providerContext, Object... contextParams); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/ResponseInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/ResponseInterceptor.java new file mode 100644 index 0000000..c16d0eb --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/ResponseInterceptor.java @@ -0,0 +1,13 @@ +package com.rbkmoney.woody.api.interceptor; + +import com.rbkmoney.woody.api.trace.TraceData; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public interface ResponseInterceptor { + /** + * @return true - if response is successfully intercepted and ready for further processing; false - if interception failed and processing must be switched to response err handling + */ + boolean interceptResponse(TraceData traceData, Provider providerContext, Object... contextParams); +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/provider/ClientProviderControl.java b/woody-api/src/main/java/com/rbkmoney/woody/api/provider/ClientProviderControl.java deleted file mode 100644 index 5cab80a..0000000 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/provider/ClientProviderControl.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.rbkmoney.woody.api.provider; - -/** - * Created by vpankrashkin on 22.04.16. - */ -public interface ClientProviderControl { - void configure(T clientProvider); -} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/provider/ProviderEventInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/provider/ProviderEventInterceptor.java new file mode 100644 index 0000000..603eb6a --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/provider/ProviderEventInterceptor.java @@ -0,0 +1,37 @@ +package com.rbkmoney.woody.api.provider; + +import com.rbkmoney.woody.api.event.ClientEventType; +import com.rbkmoney.woody.api.event.ServiceEventType; +import com.rbkmoney.woody.api.interceptor.CommonInterceptor; +import com.rbkmoney.woody.api.trace.MetadataProperties; +import com.rbkmoney.woody.api.trace.TraceData; + +/** + * Created by vpankrashkin on 27.04.16. + */ +public class ProviderEventInterceptor implements CommonInterceptor { + private final Runnable reqListener; + private final Runnable respListener; + + public ProviderEventInterceptor(Runnable reqListener, Runnable respListener) { + this.reqListener = reqListener != null ? reqListener : () -> { + }; + this.respListener = respListener != null ? respListener : () -> { + }; + } + + @Override + public boolean interceptRequest(TraceData traceData, ReqProvider providerContext, Object... contextParams) { + traceData.getActiveSpan().getMetadata().putValue(MetadataProperties.EVENT_TYPE, traceData.isClient() ? ClientEventType.CALL_SERVICE : ServiceEventType.SERVICE_RECEIVE); + reqListener.run(); + return true; + } + + @Override + public boolean interceptResponse(TraceData traceData, RespProvider providerContext, Object... contextParams) { + traceData.getActiveSpan().getMetadata().putValue(MetadataProperties.EVENT_TYPE, traceData.isClient() ? ClientEventType.SERVICE_RESULT : ServiceEventType.HANDLER_RESULT); + respListener.run(); + return true; + } + +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/HandleMethodCallerFactory.java b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/HandleMethodCallerFactory.java index c12f3d5..95a5827 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/HandleMethodCallerFactory.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/HandleMethodCallerFactory.java @@ -18,7 +18,7 @@ public class HandleMethodCallerFactory implements MethodCallerFactory { MethodHandle mh = MethodHandles.lookup() .findVirtual(target.getClass(), method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes())).asSpreader(Object[].class, method.getParameterCount()); - return new InstanceMethodCaller() { + return new InstanceMethodCaller(method) { @Override public Object call(Object[] args) throws Throwable { diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/InstanceMethodCaller.java b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/InstanceMethodCaller.java index 7cde75c..589492e 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/InstanceMethodCaller.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/InstanceMethodCaller.java @@ -1,9 +1,21 @@ package com.rbkmoney.woody.api.proxy; +import java.lang.reflect.Method; + /** * Created by vpankrashkin on 22.04.16. */ -@FunctionalInterface -public interface InstanceMethodCaller { - Object call(Object[] args) throws Throwable; +public abstract class InstanceMethodCaller { + private final Method targetMethod; + + public InstanceMethodCaller(Method targetMethod) { + this.targetMethod = targetMethod; + } + + public Method getTargetMethod() { + return targetMethod; + } + + public abstract Object call(Object[] args) throws Throwable; + } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallTracer.java b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallTracer.java index 9ba6550..0979d74 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallTracer.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/MethodCallTracer.java @@ -9,4 +9,5 @@ public interface MethodCallTracer { void afterCall(Object[] args, InstanceMethodCaller caller, Object result); void callError(Object[] args, InstanceMethodCaller caller, Throwable error); + } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ReflectionMethodCallerFactory.java b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ReflectionMethodCallerFactory.java index 431e79a..7652fcf 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ReflectionMethodCallerFactory.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/ReflectionMethodCallerFactory.java @@ -1,5 +1,6 @@ package com.rbkmoney.woody.api.proxy; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** @@ -9,6 +10,15 @@ public class ReflectionMethodCallerFactory implements MethodCallerFactory { @Override public InstanceMethodCaller getInstance(Object target, Method method) { method.setAccessible(true); - return (args) -> method.invoke(target, args); + return new InstanceMethodCaller(method) { + @Override + public Object call(Object[] args) throws Throwable { + try { + return method.invoke(target, args); + } catch (InvocationTargetException e) { + throw e.getCause(); + } + } + }; } } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ClientSpan.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ClientSpan.java index a1a2b4d..ae37ccd 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ClientSpan.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ClientSpan.java @@ -3,6 +3,6 @@ package com.rbkmoney.woody.api.trace; /** * Created by vpankrashkin on 21.04.16. */ -public class ClientSpan extends AbstractSpan { +public class ClientSpan extends ContextSpan { } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/AbstractSpan.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ContextSpan.java similarity index 95% rename from woody-api/src/main/java/com/rbkmoney/woody/api/trace/AbstractSpan.java rename to woody-api/src/main/java/com/rbkmoney/woody/api/trace/ContextSpan.java index 28f9755..0dcb801 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/AbstractSpan.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ContextSpan.java @@ -3,7 +3,7 @@ package com.rbkmoney.woody.api.trace; /** * Created by vpankrashkin on 22.04.16. */ -public class AbstractSpan { +public class ContextSpan { protected final Span span = new Span(); protected final Metadata metadata = new Metadata(); diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ContextUtils.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ContextUtils.java new file mode 100644 index 0000000..25473c7 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ContextUtils.java @@ -0,0 +1,64 @@ +package com.rbkmoney.woody.api.trace; + +import java.util.function.Function; + +/** + * Created by vpankrashkin on 11.05.16. + */ +public class ContextUtils { + public static T createErrIfNotIntercepted(ContextSpan span, Function errConstructor) { + Throwable err = getInterceptionError(span); + if (err != null) { + return errConstructor.apply(err); + } + return null; + } + + public static Throwable getInterceptionError(ContextSpan span) { + return getMetadataParameter(span, Throwable.class, MetadataProperties.INTERCEPTION_ERROR); + } + + public static void setInterceptionError(ContextSpan span, Throwable t) { + span.getMetadata().putValue(MetadataProperties.INTERCEPTION_ERROR, t); + } + + public static void setCallError(ContextSpan span, Throwable t) { + span.getMetadata().putValue(MetadataProperties.CALL_ERROR, t); + } + + public static Throwable getCallError(ContextSpan span) { + return getMetadataParameter(span, Throwable.class, MetadataProperties.CALL_ERROR); + } + + public static boolean hasCallErrors(ContextSpan span) { + return span.getMetadata().containsKey(MetadataProperties.CALL_ERROR); + } + + public static void tryThrowInterceptionError(ContextSpan span) throws Throwable { + Throwable t = getInterceptionError(span); + if (t != null) { + throw t; + } + } + + public static T getMetadataParameter(ContextSpan span, Class targetType, String key) { + Object obj = span.getMetadata().getValue(key); + if (obj == null) { + return null; + } else if (targetType.isAssignableFrom(obj.getClass())) { + return (T) obj; + } + return null; + } + + public static T getContextParameter(Class targetType, Object[] params, int index) { + if (params == null || params.length <= index || params[index] == null) { + return null; + } + + if (targetType.isAssignableFrom(params[index].getClass())) { + return (T) params[index]; + } + return null; + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Endpoint.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Endpoint.java index 3eecb84..44dddff 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Endpoint.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Endpoint.java @@ -3,8 +3,8 @@ package com.rbkmoney.woody.api.trace; /** * Created by vpankrashkin on 21.04.16. */ -public interface Endpoint { - S getSource(); +public interface Endpoint { + String getStringValue(); - T getTarget(); + T getValue(); } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Metadata.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Metadata.java index f2e4d1f..fe794c9 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Metadata.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Metadata.java @@ -25,6 +25,10 @@ public class Metadata { return (T) values.put(key, value); } + public boolean containsKey(String key) { + return values.containsKey(key); + } + public Collection getKeys() { return values.keySet(); } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/MetadataProperties.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/MetadataProperties.java index 6833f41..23ca884 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/MetadataProperties.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/MetadataProperties.java @@ -4,10 +4,22 @@ package com.rbkmoney.woody.api.trace; * Created by vpankrashkin on 25.04.16. */ public class MetadataProperties { - public static final String CALL_ARGUMENTS = "md_call_arguments"; public static final String INSTANCE_METHOD_CALLER = "md_instance_method_caller"; + public static final String CALL_ARGUMENTS = "md_call_arguments"; public static final String CALL_RESULT = "md_call_result"; public static final String CALL_ERROR = "md_call_error"; + public static final String CALL_NAME = "md_call_name"; + public static final String CALL_TYPE = "md_call_type"; + + public static final String CALL_ENDPOINT = "md_call_endpoint"; public static final String EVENT_TYPE = "md_event_type"; + + public static final String ERROR_TYPE = "md_error_type"; + public static final String ERROR_NAME = "md_error_name"; + public static final String ERROR_MESSAGE = "md_error_message"; + + public static final String INTERCEPTION_ERROR = "md_interception_error"; + + } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ServerSpan.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ServiceSpan.java similarity index 57% rename from woody-api/src/main/java/com/rbkmoney/woody/api/trace/ServerSpan.java rename to woody-api/src/main/java/com/rbkmoney/woody/api/trace/ServiceSpan.java index 53e0ac9..79eaa0c 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ServerSpan.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/ServiceSpan.java @@ -5,25 +5,16 @@ import java.util.concurrent.atomic.AtomicInteger; /** * Created by vpankrashkin on 21.04.16. */ -public class ServerSpan extends AbstractSpan { - private Endpoint endpoint; +public class ServiceSpan extends ContextSpan { + private final AtomicInteger counter = new AtomicInteger(); - public Endpoint getEndpoint() { - return endpoint; - } - - public void setEndpoint(Endpoint endpoint) { - this.endpoint = endpoint; - } - public AtomicInteger getCounter() { return counter; } public void reset() { super.reset(); - endpoint = null; counter.set(0); } } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/TraceData.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/TraceData.java index 4e1bcbb..47834a7 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/TraceData.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/TraceData.java @@ -4,19 +4,19 @@ package com.rbkmoney.woody.api.trace; * Created by vpankrashkin on 21.04.16. */ public class TraceData { - private ClientSpan clientSpan = new ClientSpan(); - private ServerSpan serverSpan = new ServerSpan(); + private final ClientSpan clientSpan = new ClientSpan(); + private final ServiceSpan serviceSpan = new ServiceSpan(); public ClientSpan getClientSpan() { return clientSpan; } - public ServerSpan getServerSpan() { - return serverSpan; + public ServiceSpan getServiceSpan() { + return serviceSpan; } /** - * Checks if {@link ServerSpan} is filled to determine root: + * Checks if {@link ServiceSpan} is filled to determine root: * - request initialized by server: span must be filled by server with data referred from client: has filled server span, it's not root by default -> false * - request initialized by client, produced by any server request handling event: has filled server span, it's not root -> false * - request initialized by client, not produced by any server request handling event: server span not filled, it's root -> true @@ -24,7 +24,7 @@ public class TraceData { * @return true - if root call is running; false - otherwise */ public boolean isRoot() { - return !serverSpan.isFilled(); + return !serviceSpan.isFilled(); } /** @@ -48,19 +48,19 @@ public class TraceData { * @return true - if call is running as root client or child client call for server request handling; false - if call is running in server request handing */ public boolean isClient() { - return serverSpan.isFilled() ? clientSpan.isFilled() : true; + return serviceSpan.isFilled() ? clientSpan.isFilled() : true; } - public AbstractSpan getActiveSpan() { - return isClient() ? clientSpan : serverSpan; + public ContextSpan getActiveSpan() { + return isClient() ? clientSpan : serviceSpan; } - public AbstractSpan getSpan(boolean isClient) { - return isClient ? clientSpan : serverSpan; + public ContextSpan getSpan(boolean isClient) { + return isClient ? clientSpan : serviceSpan; } public void reset() { clientSpan.reset(); - serverSpan.reset(); + serviceSpan.reset(); } } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/CompositeTracer.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/CompositeTracer.java new file mode 100644 index 0000000..af9ff37 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/CompositeTracer.java @@ -0,0 +1,43 @@ +package com.rbkmoney.woody.api.trace.context; + +import com.rbkmoney.woody.api.proxy.InstanceMethodCaller; +import com.rbkmoney.woody.api.proxy.MethodCallTracer; + +import java.util.Arrays; +import java.util.Collection; + +/** + * Created by vpankrashkin on 04.05.16. + */ +public class CompositeTracer implements MethodCallTracer { + private final MethodCallTracer[] tracers; + + public CompositeTracer(MethodCallTracer... callTracers) { + this(Arrays.asList(callTracers)); + } + + public CompositeTracer(Collection tracers) { + this.tracers = tracers.stream().toArray(MethodCallTracer[]::new); + } + + @Override + public void beforeCall(Object[] args, InstanceMethodCaller caller) { + for (int i = 0; i < tracers.length; ++i) { + tracers[i].beforeCall(args, caller); + } + } + + @Override + public void afterCall(Object[] args, InstanceMethodCaller caller, Object result) { + for (int i = 0; i < tracers.length; ++i) { + tracers[i].afterCall(args, caller, result); + } + } + + @Override + public void callError(Object[] args, InstanceMethodCaller caller, Throwable error) { + for (int i = 0; i < tracers.length; ++i) { + tracers[i].callError(args, caller, error); + } + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/ContextTracer.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/ContextTracer.java index 9616132..ff67da8 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/ContextTracer.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/ContextTracer.java @@ -5,6 +5,8 @@ import com.rbkmoney.woody.api.proxy.MethodCallTracer; /** * Created by vpankrashkin on 26.04.16. + * + * Used to control context lifecycle on interface method call and return */ public class ContextTracer implements MethodCallTracer { private final TraceContext traceContext; @@ -35,7 +37,7 @@ public class ContextTracer implements MethodCallTracer { try { targetTracer.callError(args, caller, error); } finally { - traceContext.destroy(); + traceContext.destroy(true); } } } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/EmptyTracer.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/EmptyTracer.java new file mode 100644 index 0000000..38aa2a4 --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/EmptyTracer.java @@ -0,0 +1,24 @@ +package com.rbkmoney.woody.api.trace.context; + +import com.rbkmoney.woody.api.proxy.InstanceMethodCaller; +import com.rbkmoney.woody.api.proxy.MethodCallTracer; + +/** + * Created by vpankrashkin on 04.05.16. + */ +public class EmptyTracer implements MethodCallTracer { + @Override + public void beforeCall(Object[] args, InstanceMethodCaller caller) { + + } + + @Override + public void afterCall(Object[] args, InstanceMethodCaller caller, Object result) { + + } + + @Override + public void callError(Object[] args, InstanceMethodCaller caller, Throwable error) { + + } +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/EventListenerTracer.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/EventTracer.java similarity index 61% rename from woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/EventListenerTracer.java rename to woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/EventTracer.java index 51137b3..261be1c 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/EventListenerTracer.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/EventTracer.java @@ -7,22 +7,17 @@ import com.rbkmoney.woody.api.proxy.MethodCallTracer; /** * Created by vpankrashkin on 25.04.16. */ -public class EventListenerTracer implements MethodCallTracer { +public class EventTracer implements MethodCallTracer { - private final MethodCallTracer callTracer; private final Runnable beforeCallListener; private final Runnable afterCallListener; private final Runnable errListener; - public EventListenerTracer(MethodCallTracer callTracer) { - this(callTracer, null, null, null); + public EventTracer() { + this(null, null, null); } - public EventListenerTracer(MethodCallTracer callTracer, Runnable beforeCallListener, Runnable afterCallListener, Runnable errListener) { - if (callTracer == null) { - throw new NullPointerException("Tracer or listener cannot be null"); - } - this.callTracer = callTracer; + public EventTracer(Runnable beforeCallListener, Runnable afterCallListener, Runnable errListener) { this.beforeCallListener = beforeCallListener != null ? beforeCallListener : () -> { }; this.afterCallListener = afterCallListener != null ? afterCallListener : () -> { @@ -33,19 +28,16 @@ public class EventListenerTracer implements MethodCallTracer { @Override public void beforeCall(Object[] args, InstanceMethodCaller caller) { - callTracer.beforeCall(args, caller); beforeCallListener.run(); } @Override public void afterCall(Object[] args, InstanceMethodCaller caller, Object result) { - callTracer.afterCall(args, caller, result); afterCallListener.run(); } @Override public void callError(Object[] args, InstanceMethodCaller caller, Throwable error) { - callTracer.callError(args, caller, error); errListener.run(); } } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/MetadataTracer.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/MetadataTracer.java index 4576a0a..8e4f05b 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/MetadataTracer.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/MetadataTracer.java @@ -4,6 +4,8 @@ import com.rbkmoney.woody.api.event.ClientEventType; import com.rbkmoney.woody.api.event.ServiceEventType; import com.rbkmoney.woody.api.proxy.InstanceMethodCaller; import com.rbkmoney.woody.api.proxy.MethodCallTracer; +import com.rbkmoney.woody.api.trace.ContextSpan; +import com.rbkmoney.woody.api.trace.ContextUtils; import com.rbkmoney.woody.api.trace.Metadata; import com.rbkmoney.woody.api.trace.MetadataProperties; @@ -41,7 +43,7 @@ public class MetadataTracer implements MethodCallTracer { boolean isClient = isClient(); setBeforeCall(isClient ? TraceContext.getCurrentTraceData().getClientSpan().getMetadata() : - TraceContext.getCurrentTraceData().getServerSpan().getMetadata(), + TraceContext.getCurrentTraceData().getServiceSpan().getMetadata(), args, caller, isClient); } @@ -51,7 +53,7 @@ public class MetadataTracer implements MethodCallTracer { boolean isClient = isClient(); setAfterCall(isClient ? TraceContext.getCurrentTraceData().getClientSpan().getMetadata() : - TraceContext.getCurrentTraceData().getServerSpan().getMetadata(), + TraceContext.getCurrentTraceData().getServiceSpan().getMetadata(), args, caller, result, isClient); } @@ -59,8 +61,8 @@ public class MetadataTracer implements MethodCallTracer { public void callError(Object[] args, InstanceMethodCaller caller, Throwable error) { boolean isClient = isClient(); setCallError(isClient ? - TraceContext.getCurrentTraceData().getClientSpan().getMetadata() : - TraceContext.getCurrentTraceData().getServerSpan().getMetadata(), + TraceContext.getCurrentTraceData().getClientSpan() : + TraceContext.getCurrentTraceData().getServiceSpan(), args, caller, error, isClient); } @@ -75,9 +77,9 @@ public class MetadataTracer implements MethodCallTracer { metadata.putValue(MetadataProperties.EVENT_TYPE, isClient ? ClientEventType.SERVICE_RESULT : ServiceEventType.HANDLER_RESULT); } - private void setCallError(Metadata metadata, Object[] args, InstanceMethodCaller caller, Throwable error, boolean isClient) { - metadata.putValue(MetadataProperties.CALL_ERROR, error); - metadata.putValue(MetadataProperties.EVENT_TYPE, isClient ? ClientEventType.ERROR : ServiceEventType.ERROR); + private void setCallError(ContextSpan contextSpan, Object[] args, InstanceMethodCaller caller, Throwable error, boolean isClient) { + ContextUtils.setCallError(contextSpan, error); + contextSpan.getMetadata().putValue(MetadataProperties.EVENT_TYPE, isClient ? ClientEventType.ERROR : ServiceEventType.ERROR); } private boolean isClient() { diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/TraceContext.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/TraceContext.java index ba84d6d..687552a 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/TraceContext.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/TraceContext.java @@ -34,38 +34,42 @@ public class TraceContext { } - public static TraceContext forClient(IdGenerator idGenerator, Runnable postInit, Runnable preDestroy) { - return new TraceContext(idGenerator, postInit, preDestroy); + public static TraceContext forClient(IdGenerator idGenerator, Runnable postInit, Runnable preDestroy, Runnable preErrDestroy) { + return new TraceContext(idGenerator, postInit, preDestroy, preErrDestroy); } - public static TraceContext forServer(IdGenerator idGenerator, Runnable postInit, Runnable preDestroy) { - return new TraceContext(idGenerator, postInit, preDestroy); + public static TraceContext forServer(IdGenerator idGenerator, Runnable postInit, Runnable preDestroy, Runnable preErrDestroy) { + return new TraceContext(idGenerator, postInit, preDestroy, preErrDestroy); } private final IdGenerator idGenerator; private final Runnable postInit; private final Runnable preDestroy; + private final Runnable preErrDestroy; private final boolean isAuto; private final boolean isClient; public TraceContext(IdGenerator idGenerator) { this(idGenerator, () -> { }, () -> { + }, () -> { }); } - public TraceContext(IdGenerator idGenerator, Runnable postInit, Runnable preDestroy) { + public TraceContext(IdGenerator idGenerator, Runnable postInit, Runnable preDestroy, Runnable preErrDestroy) { this.idGenerator = idGenerator; this.postInit = postInit; this.preDestroy = preDestroy; + this.preErrDestroy = preErrDestroy; this.isAuto = true; this.isClient = false; } - public TraceContext(IdGenerator idGenerator, Runnable postInit, Runnable preDestroy, boolean isClient) { + public TraceContext(IdGenerator idGenerator, Runnable postInit, Runnable preDestroy, Runnable preErrDestroy, boolean isClient) { this.idGenerator = idGenerator; this.postInit = postInit; this.preDestroy = preDestroy; + this.preErrDestroy = preErrDestroy; this.isAuto = false; this.isClient = isClient; } @@ -84,11 +88,19 @@ public class TraceContext { } public void destroy() { + destroy(false); + } + + public void destroy(boolean onError) { TraceData traceData = getCurrentTraceData(); boolean isClient = isClientDestroy(traceData); - setDuration(isClient ? traceData.getClientSpan().getSpan() : traceData.getServerSpan().getSpan()); + setDuration(isClient ? traceData.getClientSpan().getSpan() : traceData.getServiceSpan().getSpan()); try { - preDestroy.run(); + if (onError) { + preErrDestroy.run(); + } else { + preDestroy.run(); + } } finally { if (isClient) { destroyClientContext(traceData); @@ -98,10 +110,15 @@ public class TraceContext { } } + public void setDuration() { + TraceData traceData = getCurrentTraceData(); + setDuration(isClient ? traceData.getClientSpan().getSpan() : traceData.getServiceSpan().getSpan()); + } + private void initClientContext(TraceData traceData) { long timestamp = System.currentTimeMillis(); Span clientSpan = traceData.getClientSpan().getSpan(); - Span serverSpan = traceData.getServerSpan().getSpan(); + Span serverSpan = traceData.getServiceSpan().getSpan(); boolean root = traceData.isRoot(); String traceId = root ? idGenerator.generateId(timestamp) : serverSpan.getTraceId(); @@ -109,7 +126,7 @@ public class TraceContext { clientSpan.setId(traceId); clientSpan.setParentId(NO_PARENT_ID); } else { - clientSpan.setId(idGenerator.generateId(timestamp, traceData.getServerSpan().getCounter().incrementAndGet())); + clientSpan.setId(idGenerator.generateId(timestamp, traceData.getServiceSpan().getCounter().incrementAndGet())); clientSpan.setParentId(serverSpan.getId()); } clientSpan.setTraceId(traceId); @@ -122,7 +139,7 @@ public class TraceContext { private void initServerContext(TraceData traceData) { long timestamp = System.currentTimeMillis(); - traceData.getServerSpan().getSpan().setTimestamp(timestamp); + traceData.getServiceSpan().getSpan().setTimestamp(timestamp); } private void destroyServerContext(TraceData traceData) { @@ -142,19 +159,19 @@ public class TraceContext { } private boolean isClientInitAuto(TraceData traceData) { - Span serverSpan = traceData.getServerSpan().getSpan(); + Span serverSpan = traceData.getServiceSpan().getSpan(); - assert !(traceData.getClientSpan().isStarted() & traceData.getServerSpan().isStarted()); - assert !(traceData.getClientSpan().isFilled() & traceData.getServerSpan().isFilled()); + assert !(traceData.getClientSpan().isStarted() & traceData.getServiceSpan().isStarted()); + assert !(traceData.getClientSpan().isFilled() & traceData.getServiceSpan().isFilled()); return serverSpan.isFilled() ? serverSpan.isStarted() : true; } private boolean isClientDestroyAuto(TraceData traceData) { - assert !(traceData.getClientSpan().isStarted() || traceData.getServerSpan().isStarted()); + assert (traceData.getClientSpan().isStarted()); - return traceData.getServerSpan().isStarted() ? traceData.getClientSpan().isStarted() : true; + return traceData.getServiceSpan().isStarted() ? traceData.getClientSpan().isStarted() : true; } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/TransportEventInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/TransportEventInterceptor.java new file mode 100644 index 0000000..b8f3ead --- /dev/null +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/TransportEventInterceptor.java @@ -0,0 +1,37 @@ +package com.rbkmoney.woody.api.transport; + +import com.rbkmoney.woody.api.event.ClientEventType; +import com.rbkmoney.woody.api.event.ServiceEventType; +import com.rbkmoney.woody.api.interceptor.CommonInterceptor; +import com.rbkmoney.woody.api.trace.MetadataProperties; +import com.rbkmoney.woody.api.trace.TraceData; + +/** + * Created by vpankrashkin on 27.04.16. + */ +public class TransportEventInterceptor implements CommonInterceptor { + private final Runnable reqListener; + private final Runnable respListener; + + public TransportEventInterceptor(Runnable reqListener, Runnable respListener) { + this.reqListener = reqListener != null ? reqListener : () -> { + }; + this.respListener = respListener != null ? respListener : () -> { + }; + } + + @Override + public boolean interceptRequest(TraceData traceData, ReqProvider providerContext, Object... contextParams) { + traceData.getActiveSpan().getMetadata().putValue(MetadataProperties.EVENT_TYPE, traceData.isClient() ? ClientEventType.CLIENT_SEND : ServiceEventType.SERVICE_RECEIVE); + reqListener.run(); + return true; + } + + @Override + public boolean interceptResponse(TraceData traceData, RespProvider providerContext, Object... contextParams) { + traceData.getActiveSpan().getMetadata().putValue(MetadataProperties.EVENT_TYPE, traceData.isClient() ? ClientEventType.CLIENT_RECEIVE : ServiceEventType.SERVICE_RESULT); + respListener.run(); + return true; + } + +} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientRequestInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientRequestInterceptor.java deleted file mode 100644 index efa1ea7..0000000 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientRequestInterceptor.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.rbkmoney.woody.api.transport.interceptor; - -import com.rbkmoney.woody.api.trace.ClientSpan; - -/** - * Created by vpankrashkin on 22.04.16. - */ -public interface ClientRequestInterceptor extends RequestInterceptor { -} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientResponseInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientResponseInterceptor.java deleted file mode 100644 index 194989e..0000000 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ClientResponseInterceptor.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.rbkmoney.woody.api.transport.interceptor; - -import com.rbkmoney.woody.api.trace.ServerSpan; - -/** - * Created by vpankrashkin on 22.04.16. - */ -public interface ClientResponseInterceptor extends ResponseInterceptor { -} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/RequestInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/RequestInterceptor.java deleted file mode 100644 index 0d2cf3d..0000000 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/RequestInterceptor.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.rbkmoney.woody.api.transport.interceptor; - -import com.rbkmoney.woody.api.trace.AbstractSpan; - -/** - * Created by vpankrashkin on 22.04.16. - */ -public interface RequestInterceptor { - boolean interceptRequest(Context context, Transport spanContext); -} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ResponseInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ResponseInterceptor.java deleted file mode 100644 index 87edd0d..0000000 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ResponseInterceptor.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.rbkmoney.woody.api.transport.interceptor; - -import com.rbkmoney.woody.api.trace.AbstractSpan; - -/** - * Created by vpankrashkin on 22.04.16. - */ -public interface ResponseInterceptor { - void interceptResponse(Context context, Transport transport); -} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerRequestInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerRequestInterceptor.java deleted file mode 100644 index bf3ce95..0000000 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerRequestInterceptor.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.rbkmoney.woody.api.transport.interceptor; - -import com.rbkmoney.woody.api.trace.ServerSpan; - -/** - * Created by vpankrashkin on 22.04.16. - */ -public interface ServerRequestInterceptor extends RequestInterceptor { -} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerResponseIntercepor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerResponseIntercepor.java deleted file mode 100644 index 235c790..0000000 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/ServerResponseIntercepor.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.rbkmoney.woody.api.transport.interceptor; - -import com.rbkmoney.woody.api.trace.ServerSpan; - -/** - * Created by vpankrashkin on 22.04.16. - */ -public interface ServerResponseIntercepor extends ResponseInterceptor { -} diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/WrappedRequestInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/WrappedRequestInterceptor.java deleted file mode 100644 index 547c41b..0000000 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/transport/interceptor/WrappedRequestInterceptor.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.rbkmoney.woody.api.transport.interceptor; - -import com.rbkmoney.woody.api.event.ClientEventType; -import com.rbkmoney.woody.api.event.ServiceEventType; -import com.rbkmoney.woody.api.trace.AbstractSpan; -import com.rbkmoney.woody.api.trace.MetadataProperties; -import com.rbkmoney.woody.api.trace.TraceData; -import com.rbkmoney.woody.api.trace.context.TraceContext; - -/** - * Created by vpankrashkin on 27.04.16. - */ -public class WrappedRequestInterceptor implements RequestInterceptor { - private final RequestInterceptor interceptor; - private final Runnable listener; - - public WrappedRequestInterceptor(RequestInterceptor interceptor, Runnable listener) { - this.interceptor = interceptor; - this.listener = listener; - } - - @Override - public boolean interceptRequest(Context context, Transport spanContext) { - TraceData traceContext = TraceContext.getCurrentTraceData(); - boolean isClient = traceContext.isClient(); - - if (interceptor.interceptRequest(context, spanContext)) { - traceContext.getActiveSpan().getMetadata().putValue(MetadataProperties.EVENT_TYPE, isClient ? ClientEventType.CLIENT_RECEIVE : ServiceEventType.SERVICE_RECEIVE); - listener.run(); - return true; - } else { - traceContext.getActiveSpan().getMetadata().putValue(MetadataProperties.EVENT_TYPE, isClient ? ClientEventType.ERROR : ServiceEventType.ERROR); - return false; - } - } -} diff --git a/woody-api/src/test/java/com/rbkmoney/woody/api/proxy/TestProxyInvocationFactory.java b/woody-api/src/test/java/com/rbkmoney/woody/api/proxy/TestProxyInvocationFactory.java index 9eafef0..447497c 100644 --- a/woody-api/src/test/java/com/rbkmoney/woody/api/proxy/TestProxyInvocationFactory.java +++ b/woody-api/src/test/java/com/rbkmoney/woody/api/proxy/TestProxyInvocationFactory.java @@ -1,6 +1,6 @@ package com.rbkmoney.woody.api.proxy; -import com.rbkmoney.woody.api.trace.context.EventListenerTracer; +import com.rbkmoney.woody.api.trace.context.EventTracer; import org.junit.Test; import static org.junit.Assert.assertSame; @@ -37,7 +37,7 @@ public class TestProxyInvocationFactory { } }; - MethodCallTracer wrappedCallTracer = new EventListenerTracer(callTracer); + MethodCallTracer wrappedCallTracer = new EventTracer(); ProxyFactory reflectionProxyFactory = new ProxyFactory(new ReflectionMethodCallerFactory(), wrappedCallTracer, false); ProxyFactory handleProxyFactory = new ProxyFactory(new HandleMethodCallerFactory(), wrappedCallTracer, false); diff --git a/woody-thrift/pom.xml b/woody-thrift/pom.xml index 3d24008..5d64931 100644 --- a/woody-thrift/pom.xml +++ b/woody-thrift/pom.xml @@ -11,5 +11,70 @@ woody-thrift + + + org.slf4j + slf4j-api + 1.7.21 + + + org.eclipse.jetty + jetty-quickstart + 9.3.9.M1 + + + junit + junit + 4.11 + test + + + com.rbkmoney.woody + woody-api + ${api-version} + + + org.apache.thrift + libthrift + 0.9.3-woody_b0 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + org.apache.thrift + thrift-maven-plugin + 1.0-forked + + /usr/local/bin/thrift + + + + thrift-sources + generate-sources + + compile + + + + thrift-test-sources + generate-test-sources + + testCompile + + + + + + rpc-lib + \ No newline at end of file diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/ErrorCallType.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/ErrorCallType.java deleted file mode 100644 index 5d3112e..0000000 --- a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/ErrorCallType.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.rbkmoney.woody.thrift; - -/** - * Created by vpankrashkin on 22.04.16. - *

- * Custom error call constants, specific for - */ -public enum ErrorCallType { - /** - * Any thrift errors (protocol, transport, etc). - */ - PROVIDER_ERROR, - - /** - * Error which is registered in service method declaration. - */ - APPLICATION_KNOWN_ERROR, - - /** - * Any other error which is not registered for calling method and doesn't refer to thrift errors. - */ - APPLICATION_UNKNOWN_ERROR - -} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/TErrorType.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/TErrorType.java new file mode 100644 index 0000000..ab9597e --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/TErrorType.java @@ -0,0 +1,11 @@ +package com.rbkmoney.woody.thrift.impl.http; + +/** + * Created by vpankrashkin on 22.04.16. + */ +public enum TErrorType { + UNKNOWN_CALL, + TRANSPORT, + PROTOCOL, + UNKNOWN +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THClientBuilder.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THClientBuilder.java new file mode 100644 index 0000000..57aa200 --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THClientBuilder.java @@ -0,0 +1,149 @@ +package com.rbkmoney.woody.thrift.impl.http; + +import com.rbkmoney.woody.api.AbstractClientBuilder; +import com.rbkmoney.woody.api.event.ClientEventListener; +import com.rbkmoney.woody.api.interceptor.BasicCommonInterceptor; +import com.rbkmoney.woody.api.interceptor.CommonInterceptor; +import com.rbkmoney.woody.api.interceptor.CompositeInterceptor; +import com.rbkmoney.woody.api.provider.ProviderEventInterceptor; +import com.rbkmoney.woody.api.proxy.InstanceMethodCaller; +import com.rbkmoney.woody.api.proxy.MethodCallTracer; +import com.rbkmoney.woody.api.trace.context.EmptyTracer; +import com.rbkmoney.woody.api.trace.context.TraceContext; +import com.rbkmoney.woody.api.transport.TransportEventInterceptor; +import com.rbkmoney.woody.thrift.impl.http.event.THClientEvent; +import com.rbkmoney.woody.thrift.impl.http.interceptor.THCMessageRequestInterceptor; +import com.rbkmoney.woody.thrift.impl.http.interceptor.THCMessageResponseInterceptor; +import com.rbkmoney.woody.thrift.impl.http.interceptor.THCRequestInterceptor; +import com.rbkmoney.woody.thrift.impl.http.interceptor.THCResponseInterceptor; +import org.apache.http.client.HttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.thrift.TServiceClient; +import org.apache.thrift.protocol.TCompactProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.transport.THttpClient; +import org.apache.thrift.transport.TTransport; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.Optional; + +/** + * Created by vpankrashkin on 28.04.16. + */ +public class THClientBuilder extends AbstractClientBuilder { + private HttpClient httpClient = createHttpClient(); + + public THClientBuilder withHttpClient(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + @Override + protected MethodCallTracer getOnCallMetadataExtender(Class clientInterface) { + return new EmptyTracer() { + THErrorMetadataExtender metadataExtender = new THErrorMetadataExtender(clientInterface); + + @Override + public void callError(Object[] args, InstanceMethodCaller caller, Throwable error) { + metadataExtender.extendClientError(TraceContext.getCurrentTraceData()); + } + }; + } + + @Override + protected Runnable getErrorListener() { + return createEventRunnable(getEventListener()); + } + + @Override + protected Runnable getOnCallStartEventListener() { + return createEventRunnable(getEventListener()); + } + + @Override + protected Runnable getOnCallEndEventListener() { + return createEventRunnable(getEventListener()); + } + + @Override + protected Runnable getOnSendEventListener() { + return createEventRunnable(getEventListener()); + } + + @Override + protected Runnable getOnReceiveEventListener() { + return createEventRunnable(getEventListener()); + } + + @Override + protected T createProviderClient(Class clientInterface) { + try { + THttpClient tHttpClient = new THttpClient(getAddress().toString(), httpClient, createTransportInterceptor()); + TProtocol tProtocol = createProtocol(tHttpClient); + return createThriftClient(clientInterface, tProtocol, createMessageInterceptor()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected ProxyBuilder createProxyBuilder(Class clientInterface) { + ProxyBuilder proxyBuilder = super.createProxyBuilder(clientInterface); + proxyBuilder.setStartEventPhases(ProxyBuilder.EVENT_DISABLE); + proxyBuilder.setEndEventPhases(ProxyBuilder.EVENT_BEFORE_CONTEXT_DESTROY); + return proxyBuilder; + } + + protected TProtocol createProtocol(TTransport tTransport) { + return new TCompactProtocol(tTransport); + } + + protected HttpClient createHttpClient() { + return HttpClientBuilder.create().build(); + } + + protected CommonInterceptor createMessageInterceptor() { + return new CompositeInterceptor( + new BasicCommonInterceptor(new THCMessageRequestInterceptor(), new THCMessageResponseInterceptor()), + new ProviderEventInterceptor(getOnCallStartEventListener(), null) + ); + } + + protected CommonInterceptor createTransportInterceptor() { + return new CompositeInterceptor( + new BasicCommonInterceptor(new THCRequestInterceptor(), new THCResponseInterceptor()), + new TransportEventInterceptor(getOnSendEventListener(), getOnReceiveEventListener()) + ); + } + + protected static T createThriftClient(Class clientIface, TProtocol tProtocol, CommonInterceptor interceptor) { + try { + Optional clientClass = Arrays.stream(clientIface.getDeclaringClass().getClasses()) + .filter(cl -> cl.getSimpleName().equals("Client")).findFirst(); + if (!clientClass.isPresent()) { + throw new IllegalArgumentException("Client interface doesn't conform to Thrift generated class structure"); + } + if (!TServiceClient.class.isAssignableFrom(clientClass.get())) { + throw new IllegalArgumentException("Client class doesn't conform to Thrift generated class structure"); + } + if (!clientIface.isAssignableFrom(clientClass.get())) { + throw new IllegalArgumentException("Client class has wrong type which is not assignable to client interface"); + } + Constructor constructor = clientClass.get().getConstructor(TProtocol.class); + if (constructor == null) { + throw new IllegalArgumentException("Client class doesn't have required constructor to be created"); + } + TServiceClient tClient = (TServiceClient) constructor.newInstance(tProtocol); + tClient.setInterceptor(interceptor); + return (T) tClient; + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new IllegalArgumentException("Failed to create provider client", e); + } + } + + private Runnable createEventRunnable(ClientEventListener eventListener) { + return () -> eventListener.notifyEvent(new THClientEvent(TraceContext.getCurrentTraceData())); + } +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THErrorMetadataExtender.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THErrorMetadataExtender.java new file mode 100644 index 0000000..13b7f07 --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THErrorMetadataExtender.java @@ -0,0 +1,190 @@ +package com.rbkmoney.woody.thrift.impl.http; + +import com.rbkmoney.woody.api.event.ErrorType; +import com.rbkmoney.woody.api.proxy.InstanceMethodCaller; +import com.rbkmoney.woody.api.proxy.MethodShadow; +import com.rbkmoney.woody.api.trace.*; +import com.rbkmoney.woody.thrift.impl.http.interceptor.THRequestInterceptionException; +import org.apache.thrift.TApplicationException; +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TStruct; +import org.apache.thrift.transport.TTransportException; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Function; + +/** + * Created by vpankrashkin on 29.04.16. + */ +public class THErrorMetadataExtender { + private static final String UNKNOWN_ERROR_MESSAGE = "thrift application exception unknown"; + + private final Map errorsMap; + + public THErrorMetadataExtender(Class iface) { + this.errorsMap = getDeclaredErrorsMap(iface); + } + + public TraceData extendClientError(TraceData traceData) { + + extendError(traceData.getClientSpan(), (traceData1 -> { + Metadata metadata = traceData.getClientSpan().getMetadata(); + Throwable callErr = ContextUtils.getCallError(traceData.getClientSpan()); + if (isWrappedError(callErr)) { + extendWrappedErrorMetadata(metadata, callErr); + } else { + metadata.putValue(MetadataProperties.ERROR_TYPE, ErrorType.OTHER); + metadata.putValue(MetadataProperties.ERROR_MESSAGE, UNKNOWN_ERROR_MESSAGE); + } + return traceData1; + })); + return traceData; + } + + public TraceData extendServiceError(TraceData traceData) { + extendError(traceData.getServiceSpan(), traceData1 -> { + Metadata metadata = traceData.getClientSpan().getMetadata(); + Throwable callErr = ContextUtils.getCallError(traceData.getClientSpan()); + if (isWrappedError(callErr)) { + extendWrappedErrorMetadata(metadata, callErr); + } else if (callErr instanceof THRequestInterceptionException) { + metadata.putValue(MetadataProperties.ERROR_TYPE, ErrorType.PROVIDER_ERROR); + metadata.putValue(THMetadataProperties.TH_ERROR_TYPE, TErrorType.TRANSPORT); + metadata.putValue(THMetadataProperties.TH_ERROR_SUBTYPE, ((THRequestInterceptionException) callErr).getErrorType()); + } else { + metadata.putValue(MetadataProperties.ERROR_TYPE, ErrorType.APPLICATION_UNKNOWN_ERROR); + metadata.putValue(MetadataProperties.ERROR_MESSAGE, UNKNOWN_ERROR_MESSAGE); + + } + return traceData1; + }); + return traceData; + } + + private void extendError(ContextSpan contextSpan, Function undeclaredErrExtender) { + Metadata metadata = contextSpan.getMetadata(); + Throwable callErr = ContextUtils.getCallError(contextSpan); + if (callErr == null) { + return; + } + + InstanceMethodCaller caller = getCaller(metadata); + if (caller == null) { + return; + } + + Throwable previousErr = ContextUtils.getMetadataParameter(contextSpan, Throwable.class, THMetadataProperties.TH_ERROR_METADATA_SOURCE); + + if (callErr == previousErr) { + return; + } else { + contextSpan.getMetadata().removeValue(THMetadataProperties.TH_TRANSPORT_RESPONSE_SET); + } + metadata.putValue(MetadataProperties.ERROR_MESSAGE, callErr.getMessage()); + if (isDeclaredError(callErr.getClass(), caller.getTargetMethod())) { + extendDeclaredErrorMetadata(metadata, callErr); + } else { + undeclaredErrExtender.apply(contextSpan); + } + return; + } + + private void extendDeclaredErrorMetadata(Metadata metadata, Throwable err) { + metadata.putValue(MetadataProperties.ERROR_TYPE, ErrorType.APPLICATION_KNOWN_ERROR); + metadata.putValue(MetadataProperties.ERROR_NAME, getDeclaredErrName(err)); + } + + private void extendWrappedErrorMetadata(Metadata metadata, Throwable err) { + ErrorType errorType; + TErrorType tErrorType = null; + String errMessage; + if (err instanceof TApplicationException) { + TApplicationException appError = (TApplicationException) err; + + switch (appError.getType()) { + case TApplicationException.INTERNAL_ERROR: + errorType = ErrorType.APPLICATION_UNKNOWN_ERROR; + errMessage = UNKNOWN_ERROR_MESSAGE; + break; + case TApplicationException.PROTOCOL_ERROR: + errorType = ErrorType.PROVIDER_ERROR; + tErrorType = TErrorType.PROTOCOL; + errMessage = err.getMessage(); + break; + case TApplicationException.UNKNOWN_METHOD: + errorType = ErrorType.PROVIDER_ERROR; + tErrorType = TErrorType.UNKNOWN_CALL; + errMessage = err.getMessage(); + break; + default: + errorType = ErrorType.PROVIDER_ERROR; + tErrorType = TErrorType.UNKNOWN; + errMessage = err.getMessage(); + break; + } + } else if (err instanceof TTransportException) { + TTransportException trError = (TTransportException) err; + errorType = ErrorType.PROVIDER_ERROR; + tErrorType = TErrorType.TRANSPORT; + errMessage = trError.getMessage(); + } else { + errorType = ErrorType.OTHER; + errMessage = err.getMessage(); + } + metadata.putValue(MetadataProperties.ERROR_TYPE, errorType); + metadata.putValue(MetadataProperties.ERROR_MESSAGE, errMessage); + if (tErrorType != null) { + metadata.putValue(THMetadataProperties.TH_ERROR_TYPE, tErrorType); + } + } + + public boolean isDeclaredError(Class errClass, Method callMethod) { + Class[] declaredErrors = errorsMap.get(callMethod); + for (int i = 0; i < declaredErrors.length; ++i) { + if (declaredErrors[i].isAssignableFrom(errClass)) { + return true; + } + } + return false; + } + + private boolean isWrappedError(Throwable t) { + return t instanceof TException; + } + + private String getDeclaredErrName(Throwable t) { + //TODO optimise this + try { + Field field = t.getClass().getDeclaredField("STRUCT_DESC"); + field.setAccessible(true); + Object struct = field.get(t); + if (struct instanceof TStruct) { + return ((TStruct) struct).name; + } + return null; + } catch (NoSuchFieldException | IllegalAccessException e) { + return null; + } + } + + private InstanceMethodCaller getCaller(Metadata metadata) { + Object callerObj = metadata.getValue(MetadataProperties.INSTANCE_METHOD_CALLER); + return (callerObj instanceof InstanceMethodCaller) ? (InstanceMethodCaller) callerObj : null; + } + + private Map getDeclaredErrorsMap(Class iface) { + Map errorsMap = new TreeMap<>(MethodShadow.METHOD_COMPARATOR); + Arrays.stream(iface.getMethods()).forEach(m -> + errorsMap.put(m, Arrays.stream(m.getExceptionTypes()) + .filter(e -> !e.getName().equals(TException.class.getName())) + .toArray(Class[]::new)) + ); + return errorsMap; + } +} + + diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THMetadataProperties.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THMetadataProperties.java new file mode 100644 index 0000000..62d13f7 --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THMetadataProperties.java @@ -0,0 +1,22 @@ +package com.rbkmoney.woody.thrift.impl.http; + +/** + * Created by vpankrashkin on 29.04.16. + */ +public class THMetadataProperties { + public static final String TH_PROPERTY_PREFIX = "md_thrift_http_"; + public static final String TH_ERROR_TYPE = TH_PROPERTY_PREFIX + "error_type"; + public static final String TH_ERROR_SUBTYPE = TH_PROPERTY_PREFIX + "error_subtype"; + + public static final String TH_RESPONSE_STATUS = TH_PROPERTY_PREFIX + "response_status"; + public static final String TH_RESPONSE_MESSAGE = TH_PROPERTY_PREFIX + "response_message"; + + public static final String TH_CALL_MSG_TYPE = TH_PROPERTY_PREFIX + "call_msg_type"; + public static final String TH_CALL_RESULT_MSG_TYPE = TH_PROPERTY_PREFIX + "call_result_msg_type"; + + public static final String TH_TRANSPORT_RESPONSE = TH_PROPERTY_PREFIX + "transport_response"; + + public static final String TH_TRANSPORT_RESPONSE_SET = TH_PROPERTY_PREFIX + "transport_response_set"; + + public static final String TH_ERROR_METADATA_SOURCE = TH_PROPERTY_PREFIX + "error_metadata_source"; +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THSProtocolWrapper.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THSProtocolWrapper.java new file mode 100644 index 0000000..fe09881 --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THSProtocolWrapper.java @@ -0,0 +1,42 @@ +package com.rbkmoney.woody.thrift.impl.http; + +import com.rbkmoney.woody.api.interceptor.CommonInterceptor; +import com.rbkmoney.woody.api.trace.context.TraceContext; +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TMessage; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolDecorator; + +/** + * Created by vpankrashkin on 10.05.16. + */ +public class THSProtocolWrapper extends TProtocolDecorator { + private final CommonInterceptor interceptor; + + /** + * Encloses the specified protocol. + * + * @param protocol All operations will be forward to this protocol. Must be non-null. + */ + public THSProtocolWrapper(TProtocol protocol, CommonInterceptor interceptor) { + super(protocol); + this.interceptor = interceptor; + } + + @Override + public TMessage readMessageBegin() throws TException { + TMessage tMessage = super.readMessageBegin(); + //todo process errors + interceptor.interceptRequest(TraceContext.getCurrentTraceData(), tMessage); + return tMessage; + } + + @Override + public void writeMessageBegin(TMessage tMessage) throws TException { + //todo process errors + interceptor.interceptResponse(TraceContext.getCurrentTraceData(), tMessage); + super.writeMessageBegin(tMessage); + } + + +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THServiceBuilder.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THServiceBuilder.java new file mode 100644 index 0000000..b800c41 --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THServiceBuilder.java @@ -0,0 +1,153 @@ +package com.rbkmoney.woody.thrift.impl.http; + +import com.rbkmoney.woody.api.AbstractServiceBuilder; +import com.rbkmoney.woody.api.event.ServiceEventListener; +import com.rbkmoney.woody.api.interceptor.BasicCommonInterceptor; +import com.rbkmoney.woody.api.interceptor.CommonInterceptor; +import com.rbkmoney.woody.api.interceptor.CompositeInterceptor; +import com.rbkmoney.woody.api.interceptor.ContextInterceptor; +import com.rbkmoney.woody.api.proxy.InstanceMethodCaller; +import com.rbkmoney.woody.api.proxy.MethodCallTracer; +import com.rbkmoney.woody.api.trace.context.EmptyTracer; +import com.rbkmoney.woody.api.trace.context.TraceContext; +import com.rbkmoney.woody.api.transport.TransportEventInterceptor; +import com.rbkmoney.woody.thrift.impl.http.event.THServiceEvent; +import com.rbkmoney.woody.thrift.impl.http.interceptor.*; +import org.apache.thrift.TProcessor; +import org.apache.thrift.protocol.TCompactProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolFactory; +import org.apache.thrift.server.TServlet; + +import javax.servlet.Servlet; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.Optional; + +/** + * Created by vpankrashkin on 28.04.16. + */ +public class THServiceBuilder extends AbstractServiceBuilder { + + + @Override + protected MethodCallTracer getOnCallMetadataExtender(Class serviceInterface) { + return new EmptyTracer() { + THErrorMetadataExtender metadataExtender = new THErrorMetadataExtender(serviceInterface); + + @Override + public void callError(Object[] args, InstanceMethodCaller caller, Throwable error) { + metadataExtender.extendServiceError(TraceContext.getCurrentTraceData()); + } + }; + } + + @Override + protected Runnable getErrorListener() { + return createEventRunnable(getEventListener()); + } + + @Override + protected Runnable getOnCallStartEventListener() { + return createEventRunnable(getEventListener()); + } + + @Override + protected Runnable getOnCallEndEventListener() { + return createEventRunnable(getEventListener()); + } + + @Override + protected Runnable getOnSendEventListener() { + return createEventRunnable(getEventListener()); + } + + @Override + protected Runnable getOnReceiveEventListener() { + return createEventRunnable(getEventListener()); + } + + @Override + protected Servlet createProviderService(Class serviceInterface, T handler) { + try { + TProcessor tProcessor = createThriftProcessor(serviceInterface, handler); + return createThriftServlet(tProcessor, createTransportInterceptor(), new THErrorMetadataExtender(serviceInterface)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected ProxyBuilder createProxyBuilder(Class clientInterface) { + ProxyBuilder proxyBuilder = super.createProxyBuilder(clientInterface); + proxyBuilder.setStartEventPhases(ProxyBuilder.EVENT_BEFORE_CALL_START); + proxyBuilder.setEndEventPhases(ProxyBuilder.EVENT_AFTER_CALL_END); + return proxyBuilder; + } + + protected CommonInterceptor createMessageInterceptor() { + return new CompositeInterceptor( + new BasicCommonInterceptor(new THSMessageRequestInterceptor(), new THSMessageResponseInterceptor()) + ); + } + + protected CommonInterceptor createTransportInterceptor() { + TraceContext traceContext = createTraceContext(); + return new CompositeInterceptor( + new BasicCommonInterceptor(new THSRequestInterceptor(), new THSResponseInterceptor(true)), + new ContextInterceptor( + traceContext, + new TransportEventInterceptor(getOnReceiveEventListener(), null) + ) + ); + } + + protected TraceContext createTraceContext() { + return TraceContext.forServer(getIdGenerator(), () -> { + }, getOnSendEventListener(), getErrorListener()); + + } + + protected TProtocolFactory wrapProtocolFactory(TProtocolFactory tProtocolFactory, CommonInterceptor commonInterceptor) { + return tTransport -> { + TProtocol tProtocol = tProtocolFactory.getProtocol(tTransport); + return new THSProtocolWrapper(tProtocol, commonInterceptor); + }; + } + + protected Servlet createThriftServlet(TProcessor tProcessor, CommonInterceptor servletInterceptor, THErrorMetadataExtender metadataExtender) { + CompositeInterceptor protInterceptor = new CompositeInterceptor( + createMessageInterceptor(), + new BasicCommonInterceptor(null, new THSResponseMetadataInterceptor(metadataExtender)), + new BasicCommonInterceptor(null, new THSResponseInterceptor(false)) + ); + TProtocolFactory tProtocolFactory = wrapProtocolFactory(new TCompactProtocol.Factory(), protInterceptor); + return new TServlet(tProcessor, tProtocolFactory, servletInterceptor); + } + + protected TProcessor createThriftProcessor(Class serviceInterface, T handler) { + try { + Optional processorClass = Arrays.stream(serviceInterface.getDeclaringClass().getClasses()) + .filter(cl -> cl.getSimpleName().equals("Processor")).findFirst(); + if (!processorClass.isPresent()) { + throw new IllegalArgumentException("Service interface doesn't conform to Thrift generated class structure"); + } + if (!TProcessor.class.isAssignableFrom(processorClass.get())) { + throw new IllegalArgumentException("Service class doesn't conform to Thrift generated class structure"); + } + Constructor constructor = processorClass.get().getConstructor(serviceInterface); + if (constructor == null) { + throw new IllegalArgumentException("Service class doesn't have required constructor to be created"); + } + TProcessor tProcessor = (TProcessor) constructor.newInstance(handler); + return tProcessor; + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new IllegalArgumentException("Failed to create provider service", e); + } + } + + private Runnable createEventRunnable(ServiceEventListener eventListener) { + return () -> eventListener.notifyEvent(new THServiceEvent(TraceContext.getCurrentTraceData())); + } +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/THClientEvent.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/THClientEvent.java new file mode 100644 index 0000000..5ace363 --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/THClientEvent.java @@ -0,0 +1,35 @@ +package com.rbkmoney.woody.thrift.impl.http.event; + +import com.rbkmoney.woody.api.event.ClientEvent; +import com.rbkmoney.woody.api.trace.TraceData; +import com.rbkmoney.woody.thrift.impl.http.TErrorType; +import com.rbkmoney.woody.thrift.impl.http.THMetadataProperties; + +/** + * Created by vpankrashkin on 06.05.16. + */ +public class THClientEvent extends ClientEvent { + public THClientEvent(TraceData traceData) { + super(traceData); + } + + public Integer getThriftCallMsgType() { + return getActiveSpan().getMetadata().getValue(THMetadataProperties.TH_CALL_MSG_TYPE); + } + + public Integer getThiftCallResultMsgType() { + return getActiveSpan().getMetadata().getValue(THMetadataProperties.TH_CALL_RESULT_MSG_TYPE); + } + + public TErrorType getThriftErrorType() { + return getActiveSpan().getMetadata().getValue(THMetadataProperties.TH_ERROR_TYPE); + } + + public Integer getThriftResponseStatus() { + return getActiveSpan().getMetadata().getValue(THMetadataProperties.TH_RESPONSE_STATUS); + } + + public String getThriftResponseMessage() { + return getActiveSpan().getMetadata().getValue(THMetadataProperties.TH_RESPONSE_MESSAGE); + } +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/THServiceEvent.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/THServiceEvent.java new file mode 100644 index 0000000..a9c3919 --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/THServiceEvent.java @@ -0,0 +1,35 @@ +package com.rbkmoney.woody.thrift.impl.http.event; + +import com.rbkmoney.woody.api.event.ServiceEvent; +import com.rbkmoney.woody.api.trace.TraceData; +import com.rbkmoney.woody.thrift.impl.http.TErrorType; +import com.rbkmoney.woody.thrift.impl.http.THMetadataProperties; + +/** + * Created by vpankrashkin on 06.05.16. + */ +public class THServiceEvent extends ServiceEvent { + public THServiceEvent(TraceData traceData) { + super(traceData); + } + + public Integer getThriftCallMsgType() { + return getActiveSpan().getMetadata().getValue(THMetadataProperties.TH_CALL_MSG_TYPE); + } + + public Integer getThiftCallResultMsgType() { + return getActiveSpan().getMetadata().getValue(THMetadataProperties.TH_CALL_RESULT_MSG_TYPE); + } + + public TErrorType getThriftErrorType() { + return getActiveSpan().getMetadata().getValue(THMetadataProperties.TH_ERROR_TYPE); + } + + public Integer getThriftResponseStatus() { + return getActiveSpan().getMetadata().getValue(THMetadataProperties.TH_RESPONSE_STATUS); + } + + public String getThriftResponseMessage() { + return getActiveSpan().getMetadata().getValue(THMetadataProperties.TH_RESPONSE_MESSAGE); + } +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCEventCommonInterceptorDEL.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCEventCommonInterceptorDEL.java new file mode 100644 index 0000000..88ece4e --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCEventCommonInterceptorDEL.java @@ -0,0 +1,33 @@ +package com.rbkmoney.woody.thrift.impl.http.interceptor; + +import com.rbkmoney.woody.api.event.ClientEventType; +import com.rbkmoney.woody.api.interceptor.CommonInterceptor; +import com.rbkmoney.woody.api.trace.MetadataProperties; +import com.rbkmoney.woody.api.trace.TraceData; + +/** + * Created by vpankrashkin on 06.05.16. + */ +public class THCEventCommonInterceptorDEL implements CommonInterceptor { + private final Runnable requestListener; + private final Runnable responseListener; + + public THCEventCommonInterceptorDEL(Runnable requestListener, Runnable responseListener) { + this.requestListener = requestListener; + this.responseListener = responseListener; + } + + @Override + public boolean interceptRequest(TraceData traceData, Object providerContext, Object... contextParams) { + traceData.getClientSpan().getMetadata().putValue(MetadataProperties.EVENT_TYPE, ClientEventType.CLIENT_SEND); + requestListener.run(); + return true; + } + + @Override + public boolean interceptResponse(TraceData traceData, Object providerContext, Object... contextParams) { + traceData.getClientSpan().getMetadata().putValue(MetadataProperties.EVENT_TYPE, ClientEventType.CLIENT_RECEIVE); + responseListener.run(); + return true; + } +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCMessageRequestInterceptor.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCMessageRequestInterceptor.java new file mode 100644 index 0000000..95a964f --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCMessageRequestInterceptor.java @@ -0,0 +1,36 @@ +package com.rbkmoney.woody.thrift.impl.http.interceptor; + +import com.rbkmoney.woody.api.event.CallType; +import com.rbkmoney.woody.api.interceptor.RequestInterceptor; +import com.rbkmoney.woody.api.trace.Metadata; +import com.rbkmoney.woody.api.trace.MetadataProperties; +import com.rbkmoney.woody.api.trace.TraceData; +import com.rbkmoney.woody.thrift.impl.http.THMetadataProperties; +import org.apache.thrift.protocol.TMessage; +import org.apache.thrift.protocol.TMessageType; + +/** + * Created by vpankrashkin on 05.05.16. + */ +public class THCMessageRequestInterceptor implements RequestInterceptor { + private final Runnable eventListener; + + public THCMessageRequestInterceptor() { + this(null); + } + + public THCMessageRequestInterceptor(Runnable eventListener) { + this.eventListener = eventListener == null ? () -> { + } : eventListener; + } + + @Override + public boolean interceptRequest(TraceData traceData, TMessage providerContext, Object... contextParams) { + Metadata metadata = traceData.getClientSpan().getMetadata(); + metadata.putValue(MetadataProperties.CALL_NAME, providerContext.name); + metadata.putValue(MetadataProperties.CALL_TYPE, providerContext.type == TMessageType.ONEWAY ? CallType.CAST : CallType.CALL); + metadata.putValue(THMetadataProperties.TH_CALL_MSG_TYPE, providerContext.type); + eventListener.run(); + return true; + } +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCMessageResponseInterceptor.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCMessageResponseInterceptor.java new file mode 100644 index 0000000..97f06ad --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCMessageResponseInterceptor.java @@ -0,0 +1,31 @@ +package com.rbkmoney.woody.thrift.impl.http.interceptor; + +import com.rbkmoney.woody.api.interceptor.ResponseInterceptor; +import com.rbkmoney.woody.api.trace.Metadata; +import com.rbkmoney.woody.api.trace.TraceData; +import com.rbkmoney.woody.thrift.impl.http.THMetadataProperties; +import org.apache.thrift.protocol.TMessage; + +/** + * Created by vpankrashkin on 05.05.16. + */ +public class THCMessageResponseInterceptor implements ResponseInterceptor { + private final Runnable eventListener; + + public THCMessageResponseInterceptor() { + this(() -> { + }); + } + + public THCMessageResponseInterceptor(Runnable eventListener) { + this.eventListener = eventListener; + } + + @Override + public boolean interceptResponse(TraceData traceData, TMessage providerContext, Object... contextParams) { + Metadata metadata = traceData.getClientSpan().getMetadata(); + metadata.putValue(THMetadataProperties.TH_CALL_RESULT_MSG_TYPE, providerContext.type); + eventListener.run(); + return true; + } +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCRequestInterceptor.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCRequestInterceptor.java new file mode 100644 index 0000000..7737ed2 --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCRequestInterceptor.java @@ -0,0 +1,64 @@ +package com.rbkmoney.woody.thrift.impl.http.interceptor; + +import com.rbkmoney.woody.api.interceptor.RequestInterceptor; +import com.rbkmoney.woody.api.trace.*; +import com.rbkmoney.woody.thrift.impl.http.transport.UrlStringEndpoint; +import org.apache.http.HttpHost; +import org.apache.http.client.methods.HttpRequestBase; + +import java.net.HttpURLConnection; +import java.util.ArrayList; + +/** + * Created by vpankrashkin on 29.04.16. + */ +public class THCRequestInterceptor implements RequestInterceptor { + @Override + public boolean interceptRequest(TraceData traceData, Object providerContext, Object... contextParams) { + if (providerContext instanceof HttpRequestBase) { + return interceptRequestBase(traceData.getClientSpan(), (HttpRequestBase) providerContext, contextParams); + } else if (providerContext instanceof HttpURLConnection) { + return interceptUrlConnection(traceData.getClientSpan(), (HttpURLConnection) providerContext, contextParams); + } + return interceptError(traceData, "Unknown type:" + providerContext.getClass()); + } + + private boolean interceptUrlConnection(ClientSpan clientSpan, HttpURLConnection connection, Object... contextParams) { + extendMetadata(clientSpan, connection.getURL().toString()); + ArrayList headers = prepareClientHeaders(clientSpan); + for (int i = 0; i < headers.size(); ++i) { + connection.setRequestProperty(headers.get(i)[0], headers.get(i)[1]); + } + return true; + } + + protected boolean interceptRequestBase(ClientSpan clientSpan, HttpRequestBase requestBase, Object... contextParams) { + HttpHost httpHost = ContextUtils.getContextParameter(HttpHost.class, contextParams, 0); + extendMetadata(clientSpan, httpHost == null ? null : httpHost.toString()); + ArrayList headers = prepareClientHeaders(clientSpan); + for (int i = 0; i < headers.size(); ++i) { + requestBase.setHeader(headers.get(i)[0], headers.get(i)[1]); + } + return true; + } + + private void extendMetadata(ClientSpan clientSpan, String url) { + clientSpan.getMetadata().putValue(MetadataProperties.CALL_ENDPOINT, new UrlStringEndpoint(url)); + } + + private ArrayList prepareClientHeaders(ClientSpan clientSpan) { + Span span = clientSpan.getSpan(); + ArrayList headers = new ArrayList<>(); + headers.add(new String[]{"x-rbk-trace-id", span.getTraceId()}); + headers.add(new String[]{"x-rbk-span-id", span.getId()}); + headers.add(new String[]{"x-rbk-parent-id", span.getParentId()}); + + return headers; + } + + private boolean interceptError(TraceData traceData, String message) { + ContextUtils.setInterceptionError(traceData.getClientSpan(), new RuntimeException(message)); + return false; + } + +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCResponseInterceptor.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCResponseInterceptor.java new file mode 100644 index 0000000..6aeb5fa --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCResponseInterceptor.java @@ -0,0 +1,48 @@ +package com.rbkmoney.woody.thrift.impl.http.interceptor; + +import com.rbkmoney.woody.api.interceptor.ResponseInterceptor; +import com.rbkmoney.woody.api.trace.ClientSpan; +import com.rbkmoney.woody.api.trace.ContextUtils; +import com.rbkmoney.woody.api.trace.TraceData; +import com.rbkmoney.woody.thrift.impl.http.THMetadataProperties; +import org.apache.http.HttpResponse; + +import java.io.IOException; +import java.net.HttpURLConnection; + +/** + * Created by vpankrashkin on 29.04.16. + */ +public class THCResponseInterceptor implements ResponseInterceptor { + @Override + public boolean interceptResponse(TraceData traceData, Object providerContext, Object... contextParams) { + if (providerContext instanceof HttpResponse) { + return interceptResponseBase(traceData.getClientSpan(), (HttpResponse) providerContext); + } else if (providerContext instanceof HttpURLConnection) { + return interceptUrlConnection(traceData.getClientSpan(), (HttpURLConnection) providerContext); + } + return interceptError(traceData.getClientSpan(), "Unknown type:" + providerContext.getClass(), null); + } + + private boolean interceptUrlConnection(ClientSpan clientSpan, HttpURLConnection connection) { + try { + clientSpan.getMetadata().putValue(THMetadataProperties.TH_RESPONSE_STATUS, connection.getResponseCode()); + clientSpan.getMetadata().putValue(THMetadataProperties.TH_RESPONSE_MESSAGE, connection.getResponseMessage()); + return true; + } catch (IOException e) { + return interceptError(clientSpan, "Failed to get response data", e); + } + } + + protected boolean interceptResponseBase(ClientSpan clientSpan, HttpResponse response) { + clientSpan.getMetadata().putValue(THMetadataProperties.TH_RESPONSE_STATUS, response.getStatusLine().getStatusCode()); + clientSpan.getMetadata().putValue(THMetadataProperties.TH_RESPONSE_MESSAGE, response.getStatusLine().getReasonPhrase()); + return true; + } + + private boolean interceptError(ClientSpan clientSpan, String message, Throwable cause) { + ContextUtils.setInterceptionError(clientSpan, cause); + return false; + } + +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THRequestInterceptionException.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THRequestInterceptionException.java new file mode 100644 index 0000000..db0daaa --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THRequestInterceptionException.java @@ -0,0 +1,19 @@ +package com.rbkmoney.woody.thrift.impl.http.interceptor; + +import com.rbkmoney.woody.thrift.impl.http.transport.TTransportErrorType; + +/** + * Created by vpankrashkin on 11.05.16. + */ +public class THRequestInterceptionException extends RuntimeException { + private TTransportErrorType errorType; + + public THRequestInterceptionException(TTransportErrorType transportErrorType) { + super(); + errorType = transportErrorType; + } + + public TTransportErrorType getErrorType() { + return errorType; + } +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSMessageRequestInterceptor.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSMessageRequestInterceptor.java new file mode 100644 index 0000000..5ae4a45 --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSMessageRequestInterceptor.java @@ -0,0 +1,36 @@ +package com.rbkmoney.woody.thrift.impl.http.interceptor; + +import com.rbkmoney.woody.api.event.CallType; +import com.rbkmoney.woody.api.interceptor.RequestInterceptor; +import com.rbkmoney.woody.api.trace.Metadata; +import com.rbkmoney.woody.api.trace.MetadataProperties; +import com.rbkmoney.woody.api.trace.TraceData; +import com.rbkmoney.woody.thrift.impl.http.THMetadataProperties; +import org.apache.thrift.protocol.TMessage; +import org.apache.thrift.protocol.TMessageType; + +/** + * Created by vpankrashkin on 05.05.16. + */ +public class THSMessageRequestInterceptor implements RequestInterceptor { + private final Runnable eventListener; + + public THSMessageRequestInterceptor() { + this(null); + } + + public THSMessageRequestInterceptor(Runnable eventListener) { + this.eventListener = eventListener == null ? () -> { + } : eventListener; + } + + @Override + public boolean interceptRequest(TraceData traceData, TMessage providerContext, Object... contextParams) { + Metadata metadata = traceData.getClientSpan().getMetadata(); + metadata.putValue(MetadataProperties.CALL_NAME, providerContext.name); + metadata.putValue(MetadataProperties.CALL_TYPE, providerContext.type == TMessageType.ONEWAY ? CallType.CAST : CallType.CALL); + metadata.putValue(THMetadataProperties.TH_CALL_MSG_TYPE, providerContext.type); + eventListener.run(); + return true; + } +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSMessageResponseInterceptor.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSMessageResponseInterceptor.java new file mode 100644 index 0000000..e61fde3 --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSMessageResponseInterceptor.java @@ -0,0 +1,31 @@ +package com.rbkmoney.woody.thrift.impl.http.interceptor; + +import com.rbkmoney.woody.api.interceptor.ResponseInterceptor; +import com.rbkmoney.woody.api.trace.Metadata; +import com.rbkmoney.woody.api.trace.TraceData; +import com.rbkmoney.woody.thrift.impl.http.THMetadataProperties; +import org.apache.thrift.protocol.TMessage; + +/** + * Created by vpankrashkin on 05.05.16. + */ +public class THSMessageResponseInterceptor implements ResponseInterceptor { + private final Runnable eventListener; + + public THSMessageResponseInterceptor() { + this(() -> { + }); + } + + public THSMessageResponseInterceptor(Runnable eventListener) { + this.eventListener = eventListener; + } + + @Override + public boolean interceptResponse(TraceData traceData, TMessage providerContext, Object... contextParams) { + Metadata metadata = traceData.getClientSpan().getMetadata(); + metadata.putValue(THMetadataProperties.TH_CALL_RESULT_MSG_TYPE, providerContext.type); + eventListener.run(); + return true; + } +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSRequestInterceptor.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSRequestInterceptor.java new file mode 100644 index 0000000..b7cd31d --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSRequestInterceptor.java @@ -0,0 +1,81 @@ +package com.rbkmoney.woody.thrift.impl.http.interceptor; + +import com.rbkmoney.woody.api.interceptor.RequestInterceptor; +import com.rbkmoney.woody.api.trace.*; +import com.rbkmoney.woody.thrift.impl.http.THMetadataProperties; +import com.rbkmoney.woody.thrift.impl.http.transport.THttpHeader; +import com.rbkmoney.woody.thrift.impl.http.transport.TTransportErrorType; +import com.rbkmoney.woody.thrift.impl.http.transport.UrlStringEndpoint; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Created by vpankrashkin on 29.04.16. + */ +public class THSRequestInterceptor implements RequestInterceptor { + @Override + public boolean interceptRequest(TraceData traceData, Object providerContext, Object... contextParams) { + if (providerContext instanceof HttpServletRequest) { + return interceptHttpRequest(traceData, (HttpServletRequest) providerContext, contextParams); + } + return interceptError(traceData, "Unknown type:" + providerContext.getClass()); + } + + protected boolean interceptHttpRequest(TraceData traceData, HttpServletRequest request, Object... contextParams) { + THttpHeader errHeader = setSpanHeaders(traceData.getServiceSpan(), request); + if (errHeader != null) { + return interceptError(traceData, new THRequestInterceptionException(TTransportErrorType.BAD_TRACE_HEADERS)); + } + extendMetadata(traceData.getServiceSpan(), request, contextParams); + return true; + } + + + private THttpHeader setSpanHeaders(ServiceSpan serviceSpan, HttpServletRequest request) { + Span span = serviceSpan.getSpan(); + String header = getSpanHeader(THttpHeader.TRACE_ID.getKeyValue(), request); + if (header == null) { + return THttpHeader.TRACE_ID; + } + span.setTraceId(header); + + header = getSpanHeader(THttpHeader.SPAN_ID.getKeyValue(), request); + if (header == null) { + return THttpHeader.SPAN_ID; + } + span.setId(header); + + header = getSpanHeader(THttpHeader.PARENT_ID.getKeyValue(), request); + span.setParentId(header); + return null; + } + + private void extendMetadata(ServiceSpan serviceSpan, HttpServletRequest request, Object... contextParams) { + StringBuffer sb = request.getRequestURL().append(request.getQueryString()); + serviceSpan.getMetadata().putValue(MetadataProperties.CALL_ENDPOINT, new UrlStringEndpoint(sb.toString())); + HttpServletResponse response = ContextUtils.getContextParameter(HttpServletResponse.class, contextParams, 0); + if (response != null) { + serviceSpan.getMetadata().putValue(THMetadataProperties.TH_TRANSPORT_RESPONSE, response); + } + } + + private String getSpanHeader(String name, HttpServletRequest request) { + String value = request.getHeader(name); + if (value == null || value.length() == 0) { + return null; + } + return value; + } + + + private boolean interceptError(TraceData traceData, String message) { + return interceptError(traceData, new RuntimeException(message)); + } + + private boolean interceptError(TraceData traceData, Throwable t) { + ContextUtils.setInterceptionError(traceData.getServiceSpan(), t); + return false; + } + +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSResponseInterceptor.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSResponseInterceptor.java new file mode 100644 index 0000000..a02fa7c --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSResponseInterceptor.java @@ -0,0 +1,146 @@ +package com.rbkmoney.woody.thrift.impl.http.interceptor; + +import com.rbkmoney.woody.api.event.ErrorType; +import com.rbkmoney.woody.api.interceptor.ResponseInterceptor; +import com.rbkmoney.woody.api.trace.*; +import com.rbkmoney.woody.thrift.impl.http.TErrorType; +import com.rbkmoney.woody.thrift.impl.http.THMetadataProperties; +import com.rbkmoney.woody.thrift.impl.http.transport.THttpHeader; +import com.rbkmoney.woody.thrift.impl.http.transport.TTransportErrorType; + +import javax.servlet.http.HttpServletResponse; + +/** + * Created by vpankrashkin on 29.04.16. + */ +public class THSResponseInterceptor implements ResponseInterceptor { + public static final String THRFIT_TRANSPORT_ERROR_MSG = "thrift transport error"; + public static final String THRFIT_PROTOCOL_ERROR_MSG = "thrift protocol error"; + public static final String UNKNOWN_PROVIDER_ERROR_MSG = "unknown provider error"; + public static final String BAD_REQUEST_HEADERS_MSG = "bad request headers"; + boolean isUseContext; + + public THSResponseInterceptor(boolean isUseContext) { + this.isUseContext = isUseContext; + } + + @Override + public boolean interceptResponse(TraceData traceData, Object providerContext, Object... contextParams) { + if (traceData.getServiceSpan().getMetadata().containsKey(THMetadataProperties.TH_TRANSPORT_RESPONSE_SET)) { + return true; + } + + HttpServletResponse response = null; + if (isUseContext) { + if (providerContext instanceof HttpServletResponse) { + response = (HttpServletResponse) providerContext; + } + } else { + response = ContextUtils.getMetadataParameter(traceData.getServiceSpan(), HttpServletResponse.class, THMetadataProperties.TH_TRANSPORT_RESPONSE); + } + + if (response == null) { + return interceptError(traceData, "Unknown type:" + providerContext.getClass()); + } + + if (response.isCommitted()) { + return true; + } + + return interceptHttpResponse(traceData.getServiceSpan(), response); + + } + + private boolean interceptHttpResponse(ServiceSpan serviceSpan, HttpServletResponse response) { + response.addHeader(THttpHeader.TRACE_ID.getKeyValue(), serviceSpan.getSpan().getTraceId()); + response.addHeader(THttpHeader.SPAN_ID.getKeyValue(), serviceSpan.getSpan().getId()); + response.addHeader(THttpHeader.PARENT_ID.getKeyValue(), serviceSpan.getSpan().getParentId()); + + int responseStatus; + String errLogicValue = null; + String errThriftValue = null; + Metadata metadata = serviceSpan.getMetadata(); + ErrorType errType = ContextUtils.getMetadataParameter(serviceSpan, ErrorType.class, MetadataProperties.ERROR_TYPE); + if (errType != null) { + switch (errType) { + case APPLICATION_KNOWN_ERROR: + responseStatus = 200; + errLogicValue = metadata.getValue(MetadataProperties.ERROR_NAME); + break; + case PROVIDER_ERROR: + TErrorType tErrorType = ContextUtils.getMetadataParameter(serviceSpan, TErrorType.class, THMetadataProperties.TH_ERROR_TYPE); + if (tErrorType != null) { + switch (tErrorType) { + case UNKNOWN_CALL: + responseStatus = 405; + errThriftValue = "Unknown method:" + metadata.getValue(MetadataProperties.CALL_NAME); + break; + case TRANSPORT: + TTransportErrorType tTransportErrorType = ContextUtils.getMetadataParameter(serviceSpan, TTransportErrorType.class, THMetadataProperties.TH_ERROR_SUBTYPE); + if (tTransportErrorType != null) { + switch (tTransportErrorType) { + case BAD_TRACE_HEADERS: + case BAD_CONTENT_TYPE: + responseStatus = 403; + errThriftValue = BAD_REQUEST_HEADERS_MSG; + break; + default: + responseStatus = 403; + errThriftValue = THRFIT_TRANSPORT_ERROR_MSG; + } + } else { + responseStatus = 403; + errThriftValue = THRFIT_TRANSPORT_ERROR_MSG; + } + break; + case PROTOCOL: + responseStatus = 406; + errThriftValue = THRFIT_PROTOCOL_ERROR_MSG; + break; + case UNKNOWN: + default: + responseStatus = 410; + errThriftValue = UNKNOWN_PROVIDER_ERROR_MSG; + break; + } + } else { + responseStatus = 410; + errThriftValue = UNKNOWN_PROVIDER_ERROR_MSG; + } + break; + case APPLICATION_UNKNOWN_ERROR: + case OTHER: + default: + responseStatus = 500; + errThriftValue = metadata.getValue(MetadataProperties.ERROR_NAME); + break; + } + } else { + responseStatus = 200; + } + + if (errLogicValue != null) { + response.addHeader(THttpHeader.ERROR_LOGIC.getKeyValue(), errLogicValue); + } + + if (errThriftValue != null) { + response.addHeader(THttpHeader.ERROR_THRIFT.getKeyValue(), errThriftValue); + } + + response.setStatus(responseStatus); + + serviceSpan.getMetadata().putValue(THMetadataProperties.TH_TRANSPORT_RESPONSE_SET, true); + + return true; + } + + private boolean interceptError(TraceData traceData, String message) { + return interceptError(traceData, new RuntimeException(message)); + } + + private boolean interceptError(TraceData traceData, Throwable cause) { + ContextUtils.setInterceptionError(traceData.getServiceSpan(), cause); + return false; + } + +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSResponseMetadataInterceptor.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSResponseMetadataInterceptor.java new file mode 100644 index 0000000..e986545 --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSResponseMetadataInterceptor.java @@ -0,0 +1,24 @@ +package com.rbkmoney.woody.thrift.impl.http.interceptor; + +import com.rbkmoney.woody.api.interceptor.ResponseInterceptor; +import com.rbkmoney.woody.api.trace.TraceData; +import com.rbkmoney.woody.thrift.impl.http.THErrorMetadataExtender; + +import javax.servlet.http.HttpServletResponse; + +/** + * Created by vpankrashkin on 11.05.16. + */ +public class THSResponseMetadataInterceptor implements ResponseInterceptor { + private final THErrorMetadataExtender metadataExtender; + + public THSResponseMetadataInterceptor(THErrorMetadataExtender metadataExtender) { + this.metadataExtender = metadataExtender; + } + + @Override + public boolean interceptResponse(TraceData traceData, HttpServletResponse providerContext, Object... contextParams) { + metadataExtender.extendServiceError(traceData); + return true; + } +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/THttpHeader.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/THttpHeader.java new file mode 100644 index 0000000..e0519dc --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/THttpHeader.java @@ -0,0 +1,22 @@ +package com.rbkmoney.woody.thrift.impl.http.transport; + +/** + * Created by vpankrashkin on 11.05.16. + */ +public enum THttpHeader { + TRACE_ID("x-rbk-trace-id"), + SPAN_ID("x-rbk-span-id"), + PARENT_ID("x-rbk-parent-id"), + ERROR_LOGIC("x-rbk-rpc-error-logic"), + ERROR_THRIFT("x-rbk-rpc-error-thrift"); + + private String value; + + THttpHeader(String name) { + this.value = name; + } + + public String getKeyValue() { + return value; + } +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/TTransportErrorType.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/TTransportErrorType.java new file mode 100644 index 0000000..3a0eab4 --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/TTransportErrorType.java @@ -0,0 +1,11 @@ +package com.rbkmoney.woody.thrift.impl.http.transport; + +/** + * Created by vpankrashkin on 11.05.16. + */ +public enum TTransportErrorType { + NO_DATA, + BAD_REQUEST_TYPE, + BAD_CONTENT_TYPE, + BAD_TRACE_HEADERS +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/TransportErrorType.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/TransportErrorType.java deleted file mode 100644 index fa2e95d..0000000 --- a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/TransportErrorType.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.rbkmoney.woody.thrift.impl.http.transport; - -/** - * Created by vpankrashkin on 22.04.16. - */ -public enum TransportErrorType { - NO_DATA, - BAD_REQUEST_TYPE, - BAD_CONTENT_TYPE - -} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/UrlStringEndpoint.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/UrlStringEndpoint.java new file mode 100644 index 0000000..a582a2d --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/transport/UrlStringEndpoint.java @@ -0,0 +1,24 @@ +package com.rbkmoney.woody.thrift.impl.http.transport; + +import com.rbkmoney.woody.api.trace.Endpoint; + +/** + * Created by vpankrashkin on 06.05.16. + */ +public class UrlStringEndpoint implements Endpoint { + private String url; + + public UrlStringEndpoint(String url) { + this.url = url; + } + + @Override + public String getStringValue() { + return url; + } + + @Override + public String getValue() { + return url; + } +} diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/OwnerServiceImpl.java b/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/OwnerServiceImpl.java new file mode 100644 index 0000000..125bb4a --- /dev/null +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/OwnerServiceImpl.java @@ -0,0 +1,33 @@ +package com.rbkmoney.woody.rpc; + +import org.apache.thrift.TException; + +/** + * Created by vpankrashkin on 19.04.16. + */ +public class OwnerServiceImpl implements OwnerService.Iface { + @Override + public Owner getOwner(int id) throws TException { + return new Owner(1, "name"); + } + + @Override + public Owner getErrOwner(int id) throws err_one, TException { + return null; + } + + @Override + public void setOwner(Owner owner) throws TException { + + } + + @Override + public void setOwnerOneway(Owner owner) throws TException { + + } + + @Override + public Owner setErrOwner(Owner owner, int id) throws TException { + return null; + } +} diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/TestHttp.java b/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/TestHttp.java new file mode 100644 index 0000000..f3b1385 --- /dev/null +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/TestHttp.java @@ -0,0 +1,72 @@ +package com.rbkmoney.woody.rpc; + +/** + * Created by vpankrashkin on 19.04.16. + */ + +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TCompactProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.server.TServlet; +import org.apache.thrift.transport.THttpClient; +import org.apache.thrift.transport.TTransportException; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class TestHttp { + + private Server server; + + @Before + public void startJetty() throws Exception { + + server = new Server(8080); + ServletContextHandler context = new ServletContextHandler(); + ServletHolder defaultServ = new ServletHolder("default", TServletExample.class); + //defaultServ.setInitParameter("resourceBase",System.getProperty("user.dir")); + //defaultServ.setInitParameter("dirAllowed","true"); + context.addServlet(defaultServ, "/"); + server.setHandler(context); + + // Start Server + server.start(); + } + + @After + public void stopJetty() { + try { + server.stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void testServlet() throws TTransportException, TException { + String servletUrl = "http://localhost:8080/"; + THttpClient thc = new THttpClient(servletUrl); + TProtocol loPFactory = new TCompactProtocol(thc); + OwnerService.Client client = new OwnerService.Client(loPFactory); + Owner bean = client.getOwner(1); + Assert.assertEquals("name", bean.getName()); + + } + + public static class TServletExample extends TServlet { + public TServletExample() { + super( + new OwnerService.Processor( + new OwnerServiceImpl()), + new TCompactProtocol.Factory() + ); + } + } + + +} diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/TestSocket.java b/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/TestSocket.java new file mode 100644 index 0000000..7c00178 --- /dev/null +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/TestSocket.java @@ -0,0 +1,88 @@ +package com.rbkmoney.woody.rpc; + +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.server.TServer; +import org.apache.thrift.server.TThreadPoolServer; +import org.apache.thrift.transport.TServerSocket; +import org.apache.thrift.transport.TSocket; +import org.apache.thrift.transport.TTransport; +import org.apache.thrift.transport.TTransportException; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.IOException; +import java.net.URISyntaxException; + +/** + * Created by vpankrashkin on 19.04.16. + */ + +public class TestSocket { + + private static final int PORT = 7911; + + @BeforeClass + @SuppressWarnings({"static-access"}) + public static void startServer() throws URISyntaxException, IOException { + // Start thrift server in a seperate thread + new Thread(new ServerExample()).start(); + try { + // wait for the server start up + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + @Test + public void testExample() throws TTransportException, TException { + TTransport transport = new TSocket("localhost", PORT); + TProtocol protocol = new TBinaryProtocol(transport); + OwnerService.Client client = new OwnerService.Client(protocol); + transport.open(); + Owner bean = client.getOwner(1); + transport.close(); + Assert.assertEquals("name", bean.getName()); + } + + public static class TestHttpClient { + public static void main(String[] args) { + try { + TTransport transport = new TSocket("localhost", PORT); + TProtocol protocol = new TBinaryProtocol(transport); + OwnerService.Client client = new OwnerService.Client(protocol); + transport.open(); + Owner bean = client.getOwner(1); + transport.close(); + System.out.println(bean); + } catch (TTransportException e) { + e.printStackTrace(); + } catch (TException e) { + e.printStackTrace(); + } + } + } + + public static class ServerExample implements Runnable { + public static void main(String[] args) { + new Thread(new ServerExample()).run(); + } + + @Override + public void run() { + try { + TServerSocket serverTransport = new TServerSocket(PORT); + OwnerService.Processor processor = new OwnerService.Processor(new OwnerServiceImpl()); + TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor)); + System.out.println("Starting server on port " + PORT); + server.serve(); + } catch (TTransportException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/AbstractClientTest.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/AbstractClientTest.java new file mode 100644 index 0000000..0ebf9bd --- /dev/null +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/AbstractClientTest.java @@ -0,0 +1,96 @@ +package com.rbkmoney.woody.thrift.impl.http; + +import com.rbkmoney.woody.api.event.ClientEventListener; +import com.rbkmoney.woody.api.generator.IdGenerator; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.thrift.TException; +import org.apache.thrift.TProcessor; +import org.apache.thrift.protocol.TCompactProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.server.TServlet; +import org.apache.thrift.transport.THttpClient; +import org.apache.thrift.transport.TTransportException; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.After; +import org.junit.Before; + +import javax.servlet.Servlet; +import java.net.URI; +import java.net.URISyntaxException; + +/** + * Created by vpankrashkin on 06.05.16. + */ +public class AbstractClientTest { + protected Server server; + protected Servlet servlet = createMutableTervlet(); + protected int serverPort = 8080; + protected TProcessor tProcessor; + + @Before + public void startJetty() throws Exception { + + server = new Server(serverPort); + ServletContextHandler context = new ServletContextHandler(); + ServletHolder defaultServ = new ServletHolder("default", servlet); + context.addServlet(defaultServ, "/"); + server.setHandler(context); + + server.start(); + } + + @After + public void stopJetty() { + try { + server.stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + protected String getUrlString() { + return "http://localhost:" + serverPort; + } + + public TServlet createTServlet(TProcessor tProcessor) { + return new TServlet(tProcessor, new TCompactProtocol.Factory()); + } + + public TServlet createMutableTervlet() { + return new TServlet(new TProcessor() { + @Override + public boolean process(TProtocol in, TProtocol out) throws TException { + return tProcessor.process(in, out); + } + }, new TCompactProtocol.Factory()); + } + + protected T createThriftClient(Class iface) throws TTransportException { + try { + THttpClient thc = new THttpClient(getUrlString(), HttpClientBuilder.create().build()); + TProtocol tProtocol = new TCompactProtocol(thc); + return THClientBuilder.createThriftClient(iface, tProtocol, null); + } catch (TTransportException e) { + throw new RuntimeException(e); + } + } + + + protected T createThriftRPCClient(Class iface, IdGenerator idGenerator, ClientEventListener eventListener) { + try { + THClientBuilder clientBuilder = new THClientBuilder(); + clientBuilder.withAddress(new URI(getUrlString())); + clientBuilder.withHttpClient(HttpClientBuilder.create().build()); + clientBuilder.withIdGenerator(idGenerator); + clientBuilder.withEventListener(eventListener); + return clientBuilder.build(iface); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + +} diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/IdGeneratorStub.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/IdGeneratorStub.java new file mode 100644 index 0000000..092617a --- /dev/null +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/IdGeneratorStub.java @@ -0,0 +1,18 @@ +package com.rbkmoney.woody.thrift.impl.http; + +import com.rbkmoney.woody.api.generator.IdGenerator; + +/** + * Created by vpankrashkin on 06.05.16. + */ +public class IdGeneratorStub implements IdGenerator { + @Override + public String generateId(long timestamp) { + return Long.toString(timestamp); + } + + @Override + public String generateId(long timestamp, int counter) { + return new StringBuilder().append(timestamp).append(':').append(counter).toString(); + } +} diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/OwnerServiceStub.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/OwnerServiceStub.java new file mode 100644 index 0000000..96b09d6 --- /dev/null +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/OwnerServiceStub.java @@ -0,0 +1,36 @@ +package com.rbkmoney.woody.thrift.impl.http; + +import com.rbkmoney.woody.rpc.Owner; +import com.rbkmoney.woody.rpc.OwnerService; +import com.rbkmoney.woody.rpc.err_one; +import org.apache.thrift.TException; + +/** + * Created by vpankrashkin on 19.04.16. + */ +public class OwnerServiceStub implements OwnerService.Iface { + @Override + public Owner getOwner(int id) throws TException { + return null; + } + + @Override + public Owner getErrOwner(int id) throws err_one, TException { + return null; + } + + @Override + public void setOwner(Owner owner) throws TException { + + } + + @Override + public void setOwnerOneway(Owner owner) throws TException { + + } + + @Override + public Owner setErrOwner(Owner owner, int id) throws TException { + return null; + } +} diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestClientErrHandling.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestClientErrHandling.java new file mode 100644 index 0000000..46827f5 --- /dev/null +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestClientErrHandling.java @@ -0,0 +1,176 @@ +package com.rbkmoney.woody.thrift.impl.http; + +import com.rbkmoney.woody.api.event.CallType; +import com.rbkmoney.woody.api.event.ClientEvent; +import com.rbkmoney.woody.api.event.ErrorType; +import com.rbkmoney.woody.api.generator.IdGenerator; +import com.rbkmoney.woody.rpc.Owner; +import com.rbkmoney.woody.rpc.OwnerService; +import com.rbkmoney.woody.rpc.err_one; +import com.rbkmoney.woody.thrift.impl.http.event.THClientEvent; +import org.apache.thrift.TException; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Created by vpankrashkin on 06.05.16. + */ +public class TestClientErrHandling extends AbstractClientTest { + { + + tProcessor = new OwnerService.Processor<>(new + + OwnerServiceStub() { + @Override + public Owner getOwner(int id) throws TException { + switch (id) { + case 0: + throw new RuntimeException("err"); + case 1: + return new Owner(1, "name1"); + default: + return new Owner(-1, "default"); + } + } + + @Override + public Owner getErrOwner(int id) throws err_one { + throw new err_one(id); + } + } + + ); + } + + @Test + public void testUnexpectedError() { + + OwnerService.Iface client = (OwnerService.Iface) createThriftRPCClient(OwnerService.Iface.class, new IdGeneratorStub(), (ClientEvent clientEvent) -> { + THClientEvent thClientEvent = (THClientEvent) clientEvent; + switch (thClientEvent.getEventType()) { + case CALL_SERVICE: + assertArrayEquals(new Object[]{0}, thClientEvent.getCallArguments()); + assertEquals("getOwner", thClientEvent.getCallName()); + assertEquals(CallType.CALL, thClientEvent.getCallType()); + assertEquals(IdGenerator.NO_PARENT_ID, thClientEvent.getParentId()); + assertNotNull(thClientEvent.getTraceId()); + assertEquals(thClientEvent.getTraceId(), thClientEvent.getSpanId()); + assertNull(thClientEvent.getEndpoint()); + assertNotEquals(thClientEvent.getTimeStamp(), 0); + break; + case CLIENT_SEND: + assertEquals(getUrlString(), thClientEvent.getEndpoint().getStringValue()); + break; + case CLIENT_RECEIVE: + assertEquals(new Integer(500), thClientEvent.getThriftResponseStatus()); + assertEquals("Server Error", thClientEvent.getThriftResponseMessage()); + break; + case SERVICE_RESULT: + fail("Should not be invoked on error"); + break; + case ERROR: + assertFalse(thClientEvent.isSuccessfullCall()); + assertEquals(ErrorType.PROVIDER_ERROR, thClientEvent.getErrorType()); + assertEquals(TErrorType.PROTOCOL, thClientEvent.getThriftErrorType()); + default: + } + + + }); + try { + client.getOwner(0); + } catch (TException e) { + e.printStackTrace(); + } + + } + + @Test + public void testExpectedError() { + + OwnerService.Iface client = (OwnerService.Iface) createThriftRPCClient(OwnerService.Iface.class, new IdGeneratorStub(), (ClientEvent clientEvent) -> { + THClientEvent thClientEvent = (THClientEvent) clientEvent; + switch (thClientEvent.getEventType()) { + case CALL_SERVICE: + assertArrayEquals(new Object[]{0}, thClientEvent.getCallArguments()); + assertEquals("getErrOwner", thClientEvent.getCallName()); + assertEquals(CallType.CALL, thClientEvent.getCallType()); + assertEquals(IdGenerator.NO_PARENT_ID, thClientEvent.getParentId()); + assertNotNull(thClientEvent.getTraceId()); + assertEquals(thClientEvent.getTraceId(), thClientEvent.getSpanId()); + assertNull(thClientEvent.getEndpoint()); + assertNotEquals(thClientEvent.getTimeStamp(), 0); + break; + case CLIENT_SEND: + assertEquals(getUrlString(), thClientEvent.getEndpoint().getStringValue()); + break; + case CLIENT_RECEIVE: + assertEquals(new Integer(200), thClientEvent.getThriftResponseStatus()); + assertEquals("OK", thClientEvent.getThriftResponseMessage()); + break; + case SERVICE_RESULT: + fail("Should not be invoked on error"); + break; + case ERROR: + assertFalse(thClientEvent.isSuccessfullCall()); + assertEquals(ErrorType.APPLICATION_KNOWN_ERROR, thClientEvent.getErrorType()); + assertEquals("err_one", thClientEvent.getErrorName()); + assertNull(thClientEvent.getThriftErrorType()); + default: + fail(); + } + + + }); + try { + client.getErrOwner(0); + } catch (TException e) { + e.printStackTrace(); + } + + } + + @Test + public void testGetOwnerOK() { + + OwnerService.Iface client = (OwnerService.Iface) createThriftRPCClient(OwnerService.Iface.class, new IdGeneratorStub(), (ClientEvent clientEvent) -> { + THClientEvent thClientEvent = (THClientEvent) clientEvent; + switch (thClientEvent.getEventType()) { + case CALL_SERVICE: + assertArrayEquals(new Object[]{0}, thClientEvent.getCallArguments()); + assertEquals("getOwner", thClientEvent.getCallName()); + assertEquals(CallType.CALL, thClientEvent.getCallType()); + assertEquals(IdGenerator.NO_PARENT_ID, thClientEvent.getParentId()); + assertNotNull(thClientEvent.getTraceId()); + assertEquals(thClientEvent.getTraceId(), thClientEvent.getSpanId()); + assertNull(thClientEvent.getEndpoint()); + assertNotEquals(thClientEvent.getTimeStamp(), 0); + break; + case CLIENT_SEND: + assertEquals(getUrlString(), thClientEvent.getEndpoint().getStringValue()); + break; + case CLIENT_RECEIVE: + assertEquals(new Integer(200), thClientEvent.getThriftResponseStatus()); + assertEquals("OK", thClientEvent.getThriftResponseMessage()); + break; + case SERVICE_RESULT: + assertEquals(new Owner(1, "name1"), thClientEvent.getCallResult()); + break; + case ERROR: + fail("Should not be invoked on success"); + default: + fail(); + } + + + }); + try { + client.getOwner(1); + } catch (TException e) { + e.printStackTrace(); + } + + } + +} diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestErrLoadThriftRPCClient.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestErrLoadThriftRPCClient.java new file mode 100644 index 0000000..85fd2c9 --- /dev/null +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestErrLoadThriftRPCClient.java @@ -0,0 +1,164 @@ +package com.rbkmoney.woody.thrift.impl.http; + +import com.rbkmoney.woody.api.generator.IdGenerator; +import com.rbkmoney.woody.rpc.Owner; +import com.rbkmoney.woody.rpc.OwnerService; +import com.rbkmoney.woody.rpc.err_one; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TCompactProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.server.TServlet; +import org.apache.thrift.transport.THttpClient; +import org.apache.thrift.transport.TTransportException; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.stream.IntStream; + +/** + * Created by vpankrashkin on 05.05.16. + */ +public class TestErrLoadThriftRPCClient { + + private Server server; + + @Before + public void startJetty() throws Exception { + + server = new Server(8080); + ServletContextHandler context = new ServletContextHandler(); + ServletHolder defaultServ = new ServletHolder("default", TServletExample.class); + //defaultServ.setInitParameter("resourceBase",System.getProperty("user.dir")); + //defaultServ.setInitParameter("dirAllowed","true"); + context.addServlet(defaultServ, "/"); + server.setHandler(context); + + // Start Server + server.start(); + } + + @After + public void stopJetty() { + try { + server.stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void testServlet() throws TTransportException, TException, URISyntaxException { + String servletUrl = "http://localhost:8080/"; + OwnerService.Iface tClient = createThriftClient(servletUrl); + OwnerService.Iface tRPCClient = createThriftRPCClient(servletUrl); + + try { + tClient.getErrOwner(0); + } catch (TException e) { + Assert.assertSame(e.getClass(), err_one.class); + //e.printStackTrace(); + } + + try { + tRPCClient.getErrOwner(0); + } catch (TException e) { + Assert.assertSame(e.getClass(), err_one.class); + //e.printStackTrace(); + } + + int testCount = 20000; + System.out.println("Start warmup"); + runHtriftRPC(testCount, tRPCClient); + runThrift(testCount, tClient); + System.out.println("Warmup ended."); + testCount = 10000; + runHtriftRPC(testCount, tRPCClient); + runThrift(testCount, tClient); + + testCount = 10000; + runThrift(testCount, tClient); + runHtriftRPC(testCount, tRPCClient); + + } + + private void runThrift(int testCount, OwnerService.Iface tClient) { + long start = System.currentTimeMillis(); + IntStream.range(1, testCount).forEach(i -> { + try { + tClient.getErrOwner(i); + } catch (err_one e) { + + } catch (Exception e) { + e.printStackTrace(); + } + }); + System.out.printf("Thrift: %d iterations, %d time\n", testCount, System.currentTimeMillis() - start); + + } + + private void runHtriftRPC(int testCount, OwnerService.Iface tRPCClient) { + long start = System.currentTimeMillis(); + IntStream.range(1, testCount).forEach(i -> { + try { + tRPCClient.getErrOwner(i); + } catch (err_one e) { + + } catch (Exception e) { + e.printStackTrace(); + } + }); + System.out.printf("Thrift RPC: %d iterations, %d time\n", testCount, System.currentTimeMillis() - start); + } + + public static class TServletExample extends TServlet { + public TServletExample() { + super( + new OwnerService.Processor( + new TestErrLoadThriftRPCClient.OwnerServiceImpl()), + new TCompactProtocol.Factory() + ); + } + } + + private OwnerService.Iface createThriftClient(String url) throws TTransportException { + THttpClient thc = new THttpClient(url, HttpClientBuilder.create().build()); + TProtocol loPFactory = new TCompactProtocol(thc); + return new OwnerService.Client(loPFactory); + } + + private OwnerService.Iface createThriftRPCClient(String url) throws URISyntaxException { + THClientBuilder clientBuilder = new THClientBuilder(); + clientBuilder.withAddress(new URI(url)); + clientBuilder.withHttpClient(HttpClientBuilder.create().build()); + clientBuilder.withIdGenerator(new IdGenerator() { + @Override + public String generateId(long timestamp) { + return Long.toString(timestamp); + } + + @Override + public String generateId(long timestamp, int counter) { + return new StringBuilder().append(timestamp).append(':').append(counter).toString(); + } + }); + + return clientBuilder.build(OwnerService.Iface.class); + } + + private static class OwnerServiceImpl extends OwnerServiceStub { + @Override + public Owner getErrOwner(int id) throws TException, err_one { + throw new err_one(id); + } + } + + +} diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestLoadThriftRPCClient.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestLoadThriftRPCClient.java new file mode 100644 index 0000000..d5e1181 --- /dev/null +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestLoadThriftRPCClient.java @@ -0,0 +1,169 @@ +package com.rbkmoney.woody.thrift.impl.http; + +import com.rbkmoney.woody.api.event.ClientEvent; +import com.rbkmoney.woody.api.event.ClientEventListener; +import com.rbkmoney.woody.api.event.ServiceEvent; +import com.rbkmoney.woody.api.event.ServiceEventListener; +import com.rbkmoney.woody.rpc.Owner; +import com.rbkmoney.woody.rpc.OwnerService; +import com.rbkmoney.woody.rpc.TestHttp; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TCompactProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.server.TServlet; +import org.apache.thrift.transport.THttpClient; +import org.apache.thrift.transport.TTransportException; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import javax.servlet.Servlet; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.stream.IntStream; + +/** + * Created by vpankrashkin on 05.05.16. + */ +public class TestLoadThriftRPCClient { + + private Server server; + + @Before + public void startJetty() throws Exception { + + server = new Server(8080); + ServletContextHandler context = new ServletContextHandler(); + ServletHolder defaultServ = new ServletHolder("default", TestHttp.TServletExample.class); + context.addServlet(defaultServ, "/default"); + + THServiceBuilder serviceBuilder = new THServiceBuilder(); + serviceBuilder.withIdGenerator(new IdGeneratorStub()); + serviceBuilder.withEventListener(new ServiceEventListener() { + @Override + public void notifyEvent(ServiceEvent serviceEvent) { + + } + }); + Servlet rpcServlet = serviceBuilder.build(OwnerService.Iface.class, new OwnerServiceImpl()); + ServletHolder rpcServ = new ServletHolder("rpc", rpcServlet); + context.addServlet(defaultServ, "/rpc"); + server.setHandler(context); + + // Start Server + server.start(); + } + + @After + public void stopJetty() { + try { + server.stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void testServlet() throws TTransportException, TException, URISyntaxException { + String defaultServletUrl = "http://localhost:8080/default"; + String rpcServletUrl = "http://localhost:8080/rpc"; + OwnerService.Iface tClient = createThriftClient(defaultServletUrl); + OwnerService.Iface tRPCClient = createThriftRPCClient(rpcServletUrl); + + Owner bean = tClient.getOwner(1); + Assert.assertEquals("name", bean.getName()); + bean = tRPCClient.getOwner(1); + Assert.assertEquals("name", bean.getName()); + + IntStream.range(1, 1000).forEach(i -> { + try { + tClient.getOwner(i); + tRPCClient.getOwner(i); + } catch (TException e) { + e.printStackTrace(); + } + }); + int testCount = 10000; + runHtriftRPC(testCount, tRPCClient); + runThrift(testCount, tClient); + System.out.println("Warmup ended."); + testCount = 10000; + runHtriftRPC(testCount, tRPCClient); + runThrift(testCount, tClient); + + testCount = 10000; + runThrift(testCount, tClient); + runHtriftRPC(testCount, tRPCClient); + + } + + private void runThrift(int testCount, OwnerService.Iface tClient) { + long start = System.currentTimeMillis(); + IntStream.range(1, testCount).forEach(i -> { + try { + tClient.getOwner(i); + } catch (Exception e) { + e.printStackTrace(); + } + }); + System.out.printf("Thrift: %d iterations, %d time\n", testCount, System.currentTimeMillis() - start); + + } + + private void runHtriftRPC(int testCount, OwnerService.Iface tRPCClient) { + long start = System.currentTimeMillis(); + IntStream.range(1, testCount).forEach(i -> { + try { + tRPCClient.getOwner(i); + } catch (Exception e) { + e.printStackTrace(); + } + }); + System.out.printf("Thrift RPC: %d iterations, %d time\n", testCount, System.currentTimeMillis() - start); + } + + public static class TServletExample extends TServlet { + public TServletExample() { + super( + new OwnerService.Processor( + new OwnerServiceImpl()), + new TCompactProtocol.Factory() + ); + } + } + + private OwnerService.Iface createThriftClient(String url) throws TTransportException { + THttpClient thc = new THttpClient(url, HttpClientBuilder.create().build()); + TProtocol loPFactory = new TCompactProtocol(thc); + return new OwnerService.Client(loPFactory); + } + + private OwnerService.Iface createThriftRPCClient(String url) throws URISyntaxException { + THClientBuilder clientBuilder = new THClientBuilder(); + clientBuilder.withAddress(new URI(url)); + clientBuilder.withHttpClient(HttpClientBuilder.create().build()); + clientBuilder.withIdGenerator(new IdGeneratorStub()); + clientBuilder.withEventListener(new ClientEventListener() { + @Override + public void notifyEvent(ClientEvent event) { + + } + }); + + return clientBuilder.build(OwnerService.Iface.class); + } + + private static class OwnerServiceImpl extends OwnerServiceStub { + @Override + public Owner getOwner(int id) throws TException { + return new Owner(id, "name"); + } + } + + +} diff --git a/woody-thrift/src/test/resources/jetty-logging.properties b/woody-thrift/src/test/resources/jetty-logging.properties new file mode 100644 index 0000000..7540e67 --- /dev/null +++ b/woody-thrift/src/test/resources/jetty-logging.properties @@ -0,0 +1,6 @@ +# Configure Jetty for StdErrLog Logging +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StrErrLog +# Overall Logging Level is INFO +org.eclipse.jetty.LEVEL=INFO +# Detail Logging for WebSocket +org.eclipse.jetty.websocket.LEVEL=DEBUG \ No newline at end of file diff --git a/woody-thrift/src/test/thrift/testService.thrift b/woody-thrift/src/test/thrift/testService.thrift new file mode 100644 index 0000000..aa9d875 --- /dev/null +++ b/woody-thrift/src/test/thrift/testService.thrift @@ -0,0 +1,20 @@ +namespace java com.rbkmoney.woody.rpc + +typedef i32 int // We can use typedef to get pretty names for the types we are using +struct Owner { +1:int id, +2:string name +} + +exception err_one { +1:int id +} + +service OwnerService +{ + Owner getOwner(1:int id), + Owner getErrOwner(1:int id) throws (1:err_one err), + void setOwner(1:Owner owner), + oneway void setOwnerOneway(1:Owner owner) + Owner setErrOwner(1:Owner owner, 2:int id) throws (1:err_one err) +} \ No newline at end of file From 6ab28aa624ca1a12189225087fb940a5f70acee2 Mon Sep 17 00:00:00 2001 From: Vladimir Pankrashkin Date: Thu, 12 May 2016 18:04:25 +0300 Subject: [PATCH 3/5] MSPF-16: Bug fixes, add new tests --- pom.xml | 15 ++ woody-api/pom.xml | 8 - .../rbkmoney/woody/api/event/ClientEvent.java | 5 + .../com/rbkmoney/woody/api/event/Event.java | 2 +- .../woody/api/event/ServiceEvent.java | 5 + .../woody/api/event/ServiceEventListener.java | 2 +- .../rbkmoney/woody/api/trace/Metadata.java | 2 +- .../api/trace/context/MetadataTracer.java | 2 +- .../woody/api/trace/context/TraceContext.java | 2 +- woody-thrift/pom.xml | 25 ++- .../impl/http/THErrorMetadataExtender.java | 4 +- .../thrift/impl/http/THServiceBuilder.java | 6 +- .../http/event/ClientEventLogListener.java | 42 +++++ .../http/event/ServiceEventLogListener.java | 40 +++++ .../THCEventCommonInterceptorDEL.java | 33 ---- .../interceptor/THCRequestInterceptor.java | 6 +- .../interceptor/THSRequestInterceptor.java | 6 +- .../THSResponseMetadataInterceptor.java | 6 +- ...tractClientTest.java => AbstractTest.java} | 45 ++++- .../thrift/impl/http/OwnerServiceStub.java | 6 +- .../thrift/impl/http/TestChildRequests.java | 80 +++++++++ ...ling.java => TestClientEventHandling.java} | 136 +++++++-------- .../thrift/impl/http/TestEventOrder.java | 156 ++++++++++++++++++ ...t.java => TestLoadErrThriftRPCClient.java} | 10 +- .../impl/http/TestLoadThriftRPCClient.java | 10 +- .../impl/http/event/ClientActionListener.java | 20 +++ .../http/event/ClientEventListenerImpl.java | 52 ++++++ .../http/event/ServiceActionListener.java | 20 +++ .../http/event/ServiceEventListenerImpl.java | 53 ++++++ .../src/test/resources/log4j.properties | 5 + 30 files changed, 648 insertions(+), 156 deletions(-) create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ClientEventLogListener.java create mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceEventLogListener.java delete mode 100644 woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCEventCommonInterceptorDEL.java rename woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/{AbstractClientTest.java => AbstractTest.java} (62%) create mode 100644 woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestChildRequests.java rename woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/{TestClientErrHandling.java => TestClientEventHandling.java} (75%) create mode 100644 woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestEventOrder.java rename woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/{TestErrLoadThriftRPCClient.java => TestLoadErrThriftRPCClient.java} (96%) create mode 100644 woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ClientActionListener.java create mode 100644 woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ClientEventListenerImpl.java create mode 100644 woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceActionListener.java create mode 100644 woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceEventListenerImpl.java create mode 100644 woody-thrift/src/test/resources/log4j.properties diff --git a/pom.xml b/pom.xml index ce67b99..2edbf24 100644 --- a/pom.xml +++ b/pom.xml @@ -17,5 +17,20 @@ woody-thrift + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + + \ No newline at end of file diff --git a/woody-api/pom.xml b/woody-api/pom.xml index 8fc2e7b..1d86cd9 100644 --- a/woody-api/pom.xml +++ b/woody-api/pom.xml @@ -24,14 +24,6 @@ - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - - diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEvent.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEvent.java index 436f96a..1c655f5 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEvent.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ClientEvent.java @@ -12,6 +12,11 @@ public class ClientEvent extends Event { super(traceData); } + @Override + public ClientEventType getEventType() { + return (ClientEventType) super.getEventType(); + } + @Override public ContextSpan getActiveSpan() { return getTraceData().getClientSpan(); diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/Event.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/Event.java index 76ff158..c9da41b 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/event/Event.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/Event.java @@ -16,7 +16,7 @@ public abstract class Event { return traceData; } - public ClientEventType getEventType() { + public Object getEventType() { return getActiveSpan().getMetadata().getValue(MetadataProperties.EVENT_TYPE); } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEvent.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEvent.java index 7764d10..d3a156f 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEvent.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEvent.java @@ -11,6 +11,11 @@ public class ServiceEvent extends Event { super(traceData); } + @Override + public ServiceEventType getEventType() { + return (ServiceEventType) super.getEventType(); + } + @Override public ContextSpan getActiveSpan() { return getTraceData().getServiceSpan(); diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventListener.java b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventListener.java index 423e507..7375bec 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventListener.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/event/ServiceEventListener.java @@ -4,5 +4,5 @@ package com.rbkmoney.woody.api.event; * Created by vpankrashkin on 25.04.16. */ public interface ServiceEventListener extends EventListener { - void notifyEvent(ServiceEvent serviceEvent); + void notifyEvent(ServiceEvent event); } diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Metadata.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Metadata.java index fe794c9..c2bdfc0 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Metadata.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/Metadata.java @@ -8,7 +8,7 @@ import java.util.Map; * Created by vpankrashkin on 21.04.16. */ public class Metadata { - private static final int DEFAULT_INIT_SIZE = 8; + private static final int DEFAULT_INIT_SIZE = 16; private static final float DEFAULT_LOAD_FACTOR = 0.75f; private Map values = createStore(DEFAULT_INIT_SIZE, DEFAULT_LOAD_FACTOR); diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/MetadataTracer.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/MetadataTracer.java index 8e4f05b..25d1db3 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/MetadataTracer.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/MetadataTracer.java @@ -21,7 +21,7 @@ public class MetadataTracer implements MethodCallTracer { } public static MetadataTracer forServer() { - return new MetadataTracer(true); + return new MetadataTracer(false); } public static MetadataTracer forAuto() { diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/TraceContext.java b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/TraceContext.java index 687552a..325a8f2 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/TraceContext.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/trace/context/TraceContext.java @@ -169,7 +169,7 @@ public class TraceContext { } private boolean isClientDestroyAuto(TraceData traceData) { - assert (traceData.getClientSpan().isStarted()); + assert (traceData.getClientSpan().isStarted() || traceData.getServiceSpan().isStarted()); return traceData.getServiceSpan().isStarted() ? traceData.getClientSpan().isStarted() : true; diff --git a/woody-thrift/pom.xml b/woody-thrift/pom.xml index 5d64931..200cf1c 100644 --- a/woody-thrift/pom.xml +++ b/woody-thrift/pom.xml @@ -39,17 +39,26 @@ libthrift 0.9.3-woody_b0 + + org.slf4j + slf4j-api + 1.7.21 + + + org.slf4j + slf4j-log4j12 + 1.7.21 + + + + org.easymock + easymock + 3.4 + test + - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - - org.apache.thrift thrift-maven-plugin diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THErrorMetadataExtender.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THErrorMetadataExtender.java index 13b7f07..d65b650 100644 --- a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THErrorMetadataExtender.java +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THErrorMetadataExtender.java @@ -47,8 +47,8 @@ public class THErrorMetadataExtender { public TraceData extendServiceError(TraceData traceData) { extendError(traceData.getServiceSpan(), traceData1 -> { - Metadata metadata = traceData.getClientSpan().getMetadata(); - Throwable callErr = ContextUtils.getCallError(traceData.getClientSpan()); + Metadata metadata = traceData.getServiceSpan().getMetadata(); + Throwable callErr = ContextUtils.getCallError(traceData.getServiceSpan()); if (isWrappedError(callErr)) { extendWrappedErrorMetadata(metadata, callErr); } else if (callErr instanceof THRequestInterceptionException) { diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THServiceBuilder.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THServiceBuilder.java index b800c41..db69721 100644 --- a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THServiceBuilder.java +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/THServiceBuilder.java @@ -71,8 +71,9 @@ public class THServiceBuilder extends AbstractServiceBuilder { @Override protected Servlet createProviderService(Class serviceInterface, T handler) { try { + THErrorMetadataExtender metadataExtender = new THErrorMetadataExtender(serviceInterface); TProcessor tProcessor = createThriftProcessor(serviceInterface, handler); - return createThriftServlet(tProcessor, createTransportInterceptor(), new THErrorMetadataExtender(serviceInterface)); + return createThriftServlet(tProcessor, createTransportInterceptor(metadataExtender), metadataExtender); } catch (Exception e) { throw new RuntimeException(e); } @@ -92,9 +93,10 @@ public class THServiceBuilder extends AbstractServiceBuilder { ); } - protected CommonInterceptor createTransportInterceptor() { + protected CommonInterceptor createTransportInterceptor(THErrorMetadataExtender metadataExtender) { TraceContext traceContext = createTraceContext(); return new CompositeInterceptor( + new BasicCommonInterceptor(null, new THSResponseMetadataInterceptor(metadataExtender)), new BasicCommonInterceptor(new THSRequestInterceptor(), new THSResponseInterceptor(true)), new ContextInterceptor( traceContext, diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ClientEventLogListener.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ClientEventLogListener.java new file mode 100644 index 0000000..0c016e7 --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ClientEventLogListener.java @@ -0,0 +1,42 @@ +package com.rbkmoney.woody.thrift.impl.http.event; + +import com.rbkmoney.woody.api.event.ClientEvent; +import com.rbkmoney.woody.api.event.ClientEventListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Created by vpankrashkin on 12.05.16. + */ +public class ClientEventLogListener implements ClientEventListener { + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + @Override + public void notifyEvent(ClientEvent event1) { + THClientEvent event = (THClientEvent) event1; + try { + switch (event.getEventType()) { + case CALL_SERVICE: + log.info("CLIENT Event: {}, Span [{}-{}-{}], [{}, Type: {}], Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.getCallName(), event.getCallType(), event.getTimeStamp()); + break; + case CLIENT_SEND: + log.info("CLIENT Event: {}, Span [{}-{}-{}], Url: {}, Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.getEndpoint().getStringValue(), event.getTimeStamp()); + break; + case CLIENT_RECEIVE: + log.info("CLIENT Event: {}, Span [{}-{}-{}], Status: {}, Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.isSuccessfullCall() ? "ok" : "error", event.getTimeStamp()); + break; + case SERVICE_RESULT: + log.info("CLIENT Event: {}, Span [{}-{}-{}], Status: {}, Time: {}, Duration: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.isSuccessfullCall() ? "ok" : "error", event.getTimeStamp(), event.getDuration()); + break; + case ERROR: + log.info("CLIENT Event: {}, Span [{}-{}-{}], ErrType: {}, TErrType: {}, ErrName: {}, Time: {}, Duration: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.getErrorType(), event.getThriftErrorType(), event.getErrorName(), event.getTimeStamp(), event.getDuration()); + break; + default: + log.info("CLIENT Unknown error: {}", event); + break; + } + } catch (Exception e) { + + } + } +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceEventLogListener.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceEventLogListener.java new file mode 100644 index 0000000..46a77e8 --- /dev/null +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceEventLogListener.java @@ -0,0 +1,40 @@ +package com.rbkmoney.woody.thrift.impl.http.event; + +import com.rbkmoney.woody.api.event.ServiceEvent; +import com.rbkmoney.woody.api.event.ServiceEventListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Created by vpankrashkin on 12.05.16. + */ +public class ServiceEventLogListener implements ServiceEventListener { + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + @Override + public void notifyEvent(ServiceEvent event1) { + THServiceEvent event = (THServiceEvent) event1; + switch (event.getEventType()) { + case CALL_HANDLER: + log.info("SERVER Event: {}, Span [{}-{}-{}], [{}, Type: {}], Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.getCallName(), event.getCallType(), event.getTimeStamp()); + break; + case HANDLER_RESULT: + log.info("SERVER Event: {}, Span [{}-{}-{}], Status: {}, Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.isSuccessfullCall() ? "ok" : "error", event.getTimeStamp()); + break; + case SERVICE_RECEIVE: + log.info("SERVER Event: {}, Span [{}-{}-{}], Status: {}, Url: {}, Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.isSuccessfullCall() ? "ok" : "error", event.getEndpoint().getStringValue(), event.getTimeStamp()); + break; + case SERVICE_RESULT: + log.info("SERVER Event: {}, Span [{}-{}-{}], Status: {}, Time: {}, Duration: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.isSuccessfullCall() ? "ok" : "error", event.getTimeStamp(), event.getDuration()); + break; + case ERROR: + log.info("SERVER Event: {}, Span [{}-{}-{}], ErrType: {}, TErrType: {}, ErrName: {}, Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.getErrorType(), event.getThriftErrorType(), event.getErrorName(), event.getTimeStamp()); + break; + default: + log.info("SERVER Unknown error: {}", event); + break; + + } + + } +} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCEventCommonInterceptorDEL.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCEventCommonInterceptorDEL.java deleted file mode 100644 index 88ece4e..0000000 --- a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCEventCommonInterceptorDEL.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.rbkmoney.woody.thrift.impl.http.interceptor; - -import com.rbkmoney.woody.api.event.ClientEventType; -import com.rbkmoney.woody.api.interceptor.CommonInterceptor; -import com.rbkmoney.woody.api.trace.MetadataProperties; -import com.rbkmoney.woody.api.trace.TraceData; - -/** - * Created by vpankrashkin on 06.05.16. - */ -public class THCEventCommonInterceptorDEL implements CommonInterceptor { - private final Runnable requestListener; - private final Runnable responseListener; - - public THCEventCommonInterceptorDEL(Runnable requestListener, Runnable responseListener) { - this.requestListener = requestListener; - this.responseListener = responseListener; - } - - @Override - public boolean interceptRequest(TraceData traceData, Object providerContext, Object... contextParams) { - traceData.getClientSpan().getMetadata().putValue(MetadataProperties.EVENT_TYPE, ClientEventType.CLIENT_SEND); - requestListener.run(); - return true; - } - - @Override - public boolean interceptResponse(TraceData traceData, Object providerContext, Object... contextParams) { - traceData.getClientSpan().getMetadata().putValue(MetadataProperties.EVENT_TYPE, ClientEventType.CLIENT_RECEIVE); - responseListener.run(); - return true; - } -} diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCRequestInterceptor.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCRequestInterceptor.java index 7737ed2..e859838 100644 --- a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCRequestInterceptor.java +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THCRequestInterceptor.java @@ -3,10 +3,10 @@ package com.rbkmoney.woody.thrift.impl.http.interceptor; import com.rbkmoney.woody.api.interceptor.RequestInterceptor; import com.rbkmoney.woody.api.trace.*; import com.rbkmoney.woody.thrift.impl.http.transport.UrlStringEndpoint; -import org.apache.http.HttpHost; import org.apache.http.client.methods.HttpRequestBase; import java.net.HttpURLConnection; +import java.net.URL; import java.util.ArrayList; /** @@ -33,8 +33,8 @@ public class THCRequestInterceptor implements RequestInterceptor { } protected boolean interceptRequestBase(ClientSpan clientSpan, HttpRequestBase requestBase, Object... contextParams) { - HttpHost httpHost = ContextUtils.getContextParameter(HttpHost.class, contextParams, 0); - extendMetadata(clientSpan, httpHost == null ? null : httpHost.toString()); + URL url = ContextUtils.getContextParameter(URL.class, contextParams, 0); + extendMetadata(clientSpan, url == null ? null : url.toString()); ArrayList headers = prepareClientHeaders(clientSpan); for (int i = 0; i < headers.size(); ++i) { requestBase.setHeader(headers.get(i)[0], headers.get(i)[1]); diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSRequestInterceptor.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSRequestInterceptor.java index b7cd31d..da2f07a 100644 --- a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSRequestInterceptor.java +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSRequestInterceptor.java @@ -52,7 +52,11 @@ public class THSRequestInterceptor implements RequestInterceptor { } private void extendMetadata(ServiceSpan serviceSpan, HttpServletRequest request, Object... contextParams) { - StringBuffer sb = request.getRequestURL().append(request.getQueryString()); + String queryString = request.getQueryString(); + StringBuffer sb = request.getRequestURL(); + if (queryString != null) { + sb.append('?').append(request.getQueryString()); + } serviceSpan.getMetadata().putValue(MetadataProperties.CALL_ENDPOINT, new UrlStringEndpoint(sb.toString())); HttpServletResponse response = ContextUtils.getContextParameter(HttpServletResponse.class, contextParams, 0); if (response != null) { diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSResponseMetadataInterceptor.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSResponseMetadataInterceptor.java index e986545..a66efc8 100644 --- a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSResponseMetadataInterceptor.java +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/interceptor/THSResponseMetadataInterceptor.java @@ -4,12 +4,10 @@ import com.rbkmoney.woody.api.interceptor.ResponseInterceptor; import com.rbkmoney.woody.api.trace.TraceData; import com.rbkmoney.woody.thrift.impl.http.THErrorMetadataExtender; -import javax.servlet.http.HttpServletResponse; - /** * Created by vpankrashkin on 11.05.16. */ -public class THSResponseMetadataInterceptor implements ResponseInterceptor { +public class THSResponseMetadataInterceptor implements ResponseInterceptor { private final THErrorMetadataExtender metadataExtender; public THSResponseMetadataInterceptor(THErrorMetadataExtender metadataExtender) { @@ -17,7 +15,7 @@ public class THSResponseMetadataInterceptor implements ResponseInterceptor { +public class AbstractTest { + private HandlerCollection handlerCollection; protected Server server; - protected Servlet servlet = createMutableTervlet(); protected int serverPort = 8080; protected TProcessor tProcessor; @@ -33,14 +35,26 @@ public class AbstractClientTest { public void startJetty() throws Exception { server = new Server(serverPort); - ServletContextHandler context = new ServletContextHandler(); - ServletHolder defaultServ = new ServletHolder("default", servlet); - context.addServlet(defaultServ, "/"); - server.setHandler(context); + HandlerCollection contextHandlerCollection = new HandlerCollection(true); // important! use parameter + // mutableWhenRunning==true + this.handlerCollection = contextHandlerCollection; + server.setHandler(contextHandlerCollection); server.start(); } + protected void addServlet(Servlet servlet, String mapping) { + try { + ServletContextHandler context = new ServletContextHandler(); + ServletHolder defaultServ = new ServletHolder(mapping, servlet); + context.addServlet(defaultServ, mapping); + handlerCollection.addHandler(context); + context.start(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @After public void stopJetty() { try { @@ -68,6 +82,17 @@ public class AbstractClientTest { }, new TCompactProtocol.Factory()); } + protected Servlet createThrftRPCService(Class iface, T handler, IdGenerator idGenerator, ServiceEventListener eventListener) { + THServiceBuilder serviceBuilder = new THServiceBuilder(); + serviceBuilder.withIdGenerator(idGenerator); + serviceBuilder.withEventListener(eventListener); + return serviceBuilder.build(iface, handler); + } + + protected String getUrlString(String contextPath) { + return getUrlString() + contextPath; + } + protected T createThriftClient(Class iface) throws TTransportException { try { THttpClient thc = new THttpClient(getUrlString(), HttpClientBuilder.create().build()); @@ -78,11 +103,15 @@ public class AbstractClientTest { } } - protected T createThriftRPCClient(Class iface, IdGenerator idGenerator, ClientEventListener eventListener) { + return createThriftRPCClient(iface, idGenerator, eventListener, getUrlString()); + } + + + protected T createThriftRPCClient(Class iface, IdGenerator idGenerator, ClientEventListener eventListener, String url) { try { THClientBuilder clientBuilder = new THClientBuilder(); - clientBuilder.withAddress(new URI(getUrlString())); + clientBuilder.withAddress(new URI(url)); clientBuilder.withHttpClient(HttpClientBuilder.create().build()); clientBuilder.withIdGenerator(idGenerator); clientBuilder.withEventListener(eventListener); diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/OwnerServiceStub.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/OwnerServiceStub.java index 96b09d6..0333865 100644 --- a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/OwnerServiceStub.java +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/OwnerServiceStub.java @@ -11,12 +11,12 @@ import org.apache.thrift.TException; public class OwnerServiceStub implements OwnerService.Iface { @Override public Owner getOwner(int id) throws TException { - return null; + return new Owner(id, "" + id); } @Override public Owner getErrOwner(int id) throws err_one, TException { - return null; + throw new err_one(id); } @Override @@ -31,6 +31,6 @@ public class OwnerServiceStub implements OwnerService.Iface { @Override public Owner setErrOwner(Owner owner, int id) throws TException { - return null; + throw new err_one(id); } } diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestChildRequests.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestChildRequests.java new file mode 100644 index 0000000..550336c --- /dev/null +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestChildRequests.java @@ -0,0 +1,80 @@ +package com.rbkmoney.woody.thrift.impl.http; + +import com.rbkmoney.woody.rpc.Owner; +import com.rbkmoney.woody.rpc.OwnerService; +import com.rbkmoney.woody.rpc.err_one; +import com.rbkmoney.woody.thrift.impl.http.event.ClientEventListenerImpl; +import com.rbkmoney.woody.thrift.impl.http.event.ClientEventLogListener; +import com.rbkmoney.woody.thrift.impl.http.event.ServiceEventListenerImpl; +import com.rbkmoney.woody.thrift.impl.http.event.ServiceEventLogListener; +import org.apache.thrift.TException; +import org.apache.thrift.transport.TTransportException; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import javax.servlet.Servlet; + +import static java.lang.System.out; + +/** + * Created by vpankrashkin on 12.05.16. + */ +@Ignore +public class TestChildRequests extends AbstractTest { + + ClientEventListenerImpl clientEventListener = new ClientEventListenerImpl(); + ServiceEventListenerImpl serviceEventListener = new ServiceEventListenerImpl(); + + OwnerService.Iface client1 = createThriftRPCClient(OwnerService.Iface.class, new IdGeneratorStub(), new ClientEventLogListener(), getUrlString("/rpc")); + OwnerService.Iface client2 = createThriftRPCClient(OwnerService.Iface.class, new IdGeneratorStub(), new ClientEventLogListener(), getUrlString("/rpc")); + OwnerService.Iface handler = new OwnerServiceStub() { + @Override + public Owner getErrOwner(int id) throws TException, err_one { + switch (id) { + case 0: + Owner owner = client2.getOwner(0); + client2.setOwnerOneway(owner); + return client2.getOwner(10); + case 200: + throw new err_one(200); + case 500: + throw new RuntimeException("Test"); + default: + return super.getErrOwner(id); + } + } + }; + + Servlet servlet = createThrftRPCService(OwnerService.Iface.class, handler, new IdGeneratorStub(), new ServiceEventLogListener()); + + @Before + public void before() { + addServlet(servlet, "/rpc"); + } + + @Test + public void testEventOrder() throws TException { + out.println("Root call>"); + Assert.assertEquals(new Owner(10, "10"), client1.getErrOwner(0)); + out.println("<"); + + out.println("Root call>"); + try { + client1.getErrOwner(200); + Assert.fail(); + } catch (err_one e) { + } + out.println("<"); + out.println("Root call>"); + try { + client1.getErrOwner(500); + } catch (TTransportException e) { + } + out.println("<"); + + + } + +} diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestClientErrHandling.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestClientEventHandling.java similarity index 75% rename from woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestClientErrHandling.java rename to woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestClientEventHandling.java index 46827f5..73c3d3f 100644 --- a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestClientErrHandling.java +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestClientEventHandling.java @@ -16,78 +16,34 @@ import static org.junit.Assert.*; /** * Created by vpankrashkin on 06.05.16. */ -public class TestClientErrHandling extends AbstractClientTest { +public class TestClientEventHandling extends AbstractTest { { - tProcessor = new OwnerService.Processor<>(new + tProcessor = new OwnerService.Processor<>(new OwnerServiceStub() { + @Override + public Owner getOwner(int id) throws TException { + switch (id) { + case 0: + throw new RuntimeException("err"); + case 1: + return new Owner(1, "name1"); + default: + return new Owner(-1, "default"); + } + } - OwnerServiceStub() { - @Override - public Owner getOwner(int id) throws TException { - switch (id) { - case 0: - throw new RuntimeException("err"); - case 1: - return new Owner(1, "name1"); - default: - return new Owner(-1, "default"); - } - } - - @Override - public Owner getErrOwner(int id) throws err_one { - throw new err_one(id); - } - } + @Override + public Owner getErrOwner(int id) throws err_one { + throw new err_one(id); + } + } ); } - @Test - public void testUnexpectedError() { - - OwnerService.Iface client = (OwnerService.Iface) createThriftRPCClient(OwnerService.Iface.class, new IdGeneratorStub(), (ClientEvent clientEvent) -> { - THClientEvent thClientEvent = (THClientEvent) clientEvent; - switch (thClientEvent.getEventType()) { - case CALL_SERVICE: - assertArrayEquals(new Object[]{0}, thClientEvent.getCallArguments()); - assertEquals("getOwner", thClientEvent.getCallName()); - assertEquals(CallType.CALL, thClientEvent.getCallType()); - assertEquals(IdGenerator.NO_PARENT_ID, thClientEvent.getParentId()); - assertNotNull(thClientEvent.getTraceId()); - assertEquals(thClientEvent.getTraceId(), thClientEvent.getSpanId()); - assertNull(thClientEvent.getEndpoint()); - assertNotEquals(thClientEvent.getTimeStamp(), 0); - break; - case CLIENT_SEND: - assertEquals(getUrlString(), thClientEvent.getEndpoint().getStringValue()); - break; - case CLIENT_RECEIVE: - assertEquals(new Integer(500), thClientEvent.getThriftResponseStatus()); - assertEquals("Server Error", thClientEvent.getThriftResponseMessage()); - break; - case SERVICE_RESULT: - fail("Should not be invoked on error"); - break; - case ERROR: - assertFalse(thClientEvent.isSuccessfullCall()); - assertEquals(ErrorType.PROVIDER_ERROR, thClientEvent.getErrorType()); - assertEquals(TErrorType.PROTOCOL, thClientEvent.getThriftErrorType()); - default: - } - - - }); - try { - client.getOwner(0); - } catch (TException e) { - e.printStackTrace(); - } - - } - @Test public void testExpectedError() { + addServlet(createMutableTervlet(), "/"); OwnerService.Iface client = (OwnerService.Iface) createThriftRPCClient(OwnerService.Iface.class, new IdGeneratorStub(), (ClientEvent clientEvent) -> { THClientEvent thClientEvent = (THClientEvent) clientEvent; @@ -117,6 +73,7 @@ public class TestClientErrHandling extends AbstractClientTest { assertEquals(ErrorType.APPLICATION_KNOWN_ERROR, thClientEvent.getErrorType()); assertEquals("err_one", thClientEvent.getErrorName()); assertNull(thClientEvent.getThriftErrorType()); + break; default: fail(); } @@ -133,12 +90,13 @@ public class TestClientErrHandling extends AbstractClientTest { @Test public void testGetOwnerOK() { + addServlet(createMutableTervlet(), "/"); - OwnerService.Iface client = (OwnerService.Iface) createThriftRPCClient(OwnerService.Iface.class, new IdGeneratorStub(), (ClientEvent clientEvent) -> { + OwnerService.Iface client = createThriftRPCClient(OwnerService.Iface.class, new IdGeneratorStub(), (ClientEvent clientEvent) -> { THClientEvent thClientEvent = (THClientEvent) clientEvent; switch (thClientEvent.getEventType()) { case CALL_SERVICE: - assertArrayEquals(new Object[]{0}, thClientEvent.getCallArguments()); + assertArrayEquals(new Object[]{1}, thClientEvent.getCallArguments()); assertEquals("getOwner", thClientEvent.getCallName()); assertEquals(CallType.CALL, thClientEvent.getCallType()); assertEquals(IdGenerator.NO_PARENT_ID, thClientEvent.getParentId()); @@ -158,9 +116,8 @@ public class TestClientErrHandling extends AbstractClientTest { assertEquals(new Owner(1, "name1"), thClientEvent.getCallResult()); break; case ERROR: - fail("Should not be invoked on success"); default: - fail(); + fail("Should not be invoked on success"); } @@ -173,4 +130,49 @@ public class TestClientErrHandling extends AbstractClientTest { } + @Test + public void testUnexpectedError() { + addServlet(createMutableTervlet(), "/"); + + OwnerService.Iface client = createThriftRPCClient(OwnerService.Iface.class, new IdGeneratorStub(), (ClientEvent clientEvent) -> { + THClientEvent thClientEvent = (THClientEvent) clientEvent; + switch (thClientEvent.getEventType()) { + case CALL_SERVICE: + assertArrayEquals(new Object[]{0}, thClientEvent.getCallArguments()); + assertEquals("getOwner", thClientEvent.getCallName()); + assertEquals(CallType.CALL, thClientEvent.getCallType()); + assertEquals(IdGenerator.NO_PARENT_ID, thClientEvent.getParentId()); + assertNotNull(thClientEvent.getTraceId()); + assertEquals(thClientEvent.getTraceId(), thClientEvent.getSpanId()); + assertNull(thClientEvent.getEndpoint()); + assertNotEquals(thClientEvent.getTimeStamp(), 0); + break; + case CLIENT_SEND: + assertEquals(getUrlString(), thClientEvent.getEndpoint().getStringValue()); + break; + case CLIENT_RECEIVE: + assertEquals(new Integer(500), thClientEvent.getThriftResponseStatus()); + assertEquals("Server Error", thClientEvent.getThriftResponseMessage()); + break; + case SERVICE_RESULT: + fail("Should not be invoked on error"); + break; + case ERROR: + assertFalse(thClientEvent.isSuccessfullCall()); + assertEquals(ErrorType.PROVIDER_ERROR, thClientEvent.getErrorType()); + assertEquals(TErrorType.TRANSPORT, thClientEvent.getThriftErrorType()); + break; + default: + fail(); + } + + + }); + try { + client.getOwner(0); + } catch (TException e) { + e.printStackTrace(); + } + } + } diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestEventOrder.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestEventOrder.java new file mode 100644 index 0000000..eefe3ce --- /dev/null +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestEventOrder.java @@ -0,0 +1,156 @@ +package com.rbkmoney.woody.thrift.impl.http; + +import com.rbkmoney.woody.rpc.Owner; +import com.rbkmoney.woody.rpc.OwnerService; +import com.rbkmoney.woody.rpc.err_one; +import com.rbkmoney.woody.thrift.impl.http.event.ClientActionListener; +import com.rbkmoney.woody.thrift.impl.http.event.ClientEventListenerImpl; +import com.rbkmoney.woody.thrift.impl.http.event.ServiceActionListener; +import com.rbkmoney.woody.thrift.impl.http.event.ServiceEventListenerImpl; +import org.apache.thrift.TException; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import javax.servlet.Servlet; + +import static org.easymock.EasyMock.*; + +/** + * Created by vpankrashkin on 12.05.16. + */ +public class TestEventOrder extends AbstractTest { + + ClientEventListenerImpl clientEventListener = new ClientEventListenerImpl(); + ServiceEventListenerImpl serviceEventListener = new ServiceEventListenerImpl(); + OwnerService.Iface handler = new OwnerServiceStub() { + @Override + public Owner getErrOwner(int id) throws TException, err_one { + switch (id) { + case 500: + throw new RuntimeException("Test"); + default: + return super.getErrOwner(id); + } + } + }; + + Servlet servlet = createThrftRPCService(OwnerService.Iface.class, handler, new IdGeneratorStub(), serviceEventListener); + + OwnerService.Iface client = createThriftRPCClient(OwnerService.Iface.class, new IdGeneratorStub(), clientEventListener, getUrlString("/rpc")); + + @Before + public void before() { + addServlet(servlet, "/rpc"); + } + + @Test + public void testEventOrder() throws TException { + + ClientActionListener clientActionListener = createStrictMock(ClientActionListener.class); + expect(clientActionListener.callService(anyObject())).andReturn(null); + expect(clientActionListener.clientSend(anyObject())).andReturn(null); + expect(clientActionListener.clientReceive(anyObject())).andReturn(null); + expect(clientActionListener.serviceResult(anyObject())).andReturn(null); + replay(clientActionListener); + + ServiceActionListener serviceEventActionListener = createStrictMock(ServiceActionListener.class); + expect(serviceEventActionListener.serviceReceive(anyObject())).andReturn(null); + expect(serviceEventActionListener.callHandler(anyObject())).andReturn(null); + expect(serviceEventActionListener.handlerResult(anyObject())).andReturn(null); + expect(serviceEventActionListener.serviceResult(anyObject())).andReturn(null); + replay(serviceEventActionListener); + + clientEventListener.setEventActionListener(clientActionListener); + serviceEventListener.setEventActionListener(serviceEventActionListener); + + client.getOwner(0); + + verify(clientActionListener); + } + + @Test + public void testOneWayEventOrder() throws TException { + + ClientActionListener clientActionListener = createStrictMock(ClientActionListener.class); + expect(clientActionListener.callService(anyObject())).andReturn(null); + expect(clientActionListener.clientSend(anyObject())).andReturn(null); + expect(clientActionListener.clientReceive(anyObject())).andReturn(null); + expect(clientActionListener.serviceResult(anyObject())).andReturn(null); + replay(clientActionListener); + + ServiceActionListener serviceEventActionListener = createStrictMock(ServiceActionListener.class); + expect(serviceEventActionListener.serviceReceive(anyObject())).andReturn(null); + expect(serviceEventActionListener.callHandler(anyObject())).andReturn(null); + expect(serviceEventActionListener.handlerResult(anyObject())).andReturn(null); + expect(serviceEventActionListener.serviceResult(anyObject())).andReturn(null); + replay(serviceEventActionListener); + + clientEventListener.setEventActionListener(clientActionListener); + serviceEventListener.setEventActionListener(serviceEventActionListener); + + client.setOwnerOneway(new Owner(0, "")); + + verify(clientActionListener); + } + + @Test + public void testKnownErrEventOrder() throws TException { + + ClientActionListener clientActionListener = createStrictMock(ClientActionListener.class); + expect(clientActionListener.callService(anyObject())).andReturn(null); + expect(clientActionListener.clientSend(anyObject())).andReturn(null); + expect(clientActionListener.clientReceive(anyObject())).andReturn(null); + expect(clientActionListener.error(anyObject())).andReturn(null); + replay(clientActionListener); + + ServiceActionListener serviceEventActionListener = createStrictMock(ServiceActionListener.class); + expect(serviceEventActionListener.serviceReceive(anyObject())).andReturn(null); + expect(serviceEventActionListener.callHandler(anyObject())).andReturn(null); + expect(serviceEventActionListener.error(anyObject())).andReturn(null); + expect(serviceEventActionListener.serviceResult(anyObject())).andReturn(null); + replay(serviceEventActionListener); + + clientEventListener.setEventActionListener(clientActionListener); + serviceEventListener.setEventActionListener(serviceEventActionListener); + + try { + client.getErrOwner(1); + Assert.fail("Exception should be here"); + } catch (err_one e) { + Assert.assertEquals(1, e.getId()); + } + + verify(clientActionListener); + } + + @Test + public void testUnknownErrEventOrder() throws TException { + + ClientActionListener clientActionListener = createStrictMock(ClientActionListener.class); + expect(clientActionListener.callService(anyObject())).andReturn(null); + expect(clientActionListener.clientSend(anyObject())).andReturn(null); + expect(clientActionListener.clientReceive(anyObject())).andReturn(null); + expect(clientActionListener.error(anyObject())).andReturn(null); + replay(clientActionListener); + + ServiceActionListener serviceEventActionListener = createStrictMock(ServiceActionListener.class); + expect(serviceEventActionListener.serviceReceive(anyObject())).andReturn(null); + expect(serviceEventActionListener.callHandler(anyObject())).andReturn(null); + expect(serviceEventActionListener.error(anyObject())).andReturn(null); + expect(serviceEventActionListener.serviceResult(anyObject())).andReturn(null); + replay(serviceEventActionListener); + + clientEventListener.setEventActionListener(clientActionListener); + serviceEventListener.setEventActionListener(serviceEventActionListener); + + try { + client.getErrOwner(500); + Assert.fail("Exception should be here"); + } catch (Exception e) { + e.printStackTrace(); + } + + verify(clientActionListener); + } +} diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestErrLoadThriftRPCClient.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestLoadErrThriftRPCClient.java similarity index 96% rename from woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestErrLoadThriftRPCClient.java rename to woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestLoadErrThriftRPCClient.java index 85fd2c9..eb4b526 100644 --- a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestErrLoadThriftRPCClient.java +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestLoadErrThriftRPCClient.java @@ -14,10 +14,7 @@ import org.apache.thrift.transport.TTransportException; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.*; import java.net.URI; import java.net.URISyntaxException; @@ -26,7 +23,8 @@ import java.util.stream.IntStream; /** * Created by vpankrashkin on 05.05.16. */ -public class TestErrLoadThriftRPCClient { +@Ignore +public class TestLoadErrThriftRPCClient { private Server server; @@ -122,7 +120,7 @@ public class TestErrLoadThriftRPCClient { public TServletExample() { super( new OwnerService.Processor( - new TestErrLoadThriftRPCClient.OwnerServiceImpl()), + new TestLoadErrThriftRPCClient.OwnerServiceImpl()), new TCompactProtocol.Factory() ); } diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestLoadThriftRPCClient.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestLoadThriftRPCClient.java index d5e1181..6207c5a 100644 --- a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestLoadThriftRPCClient.java +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestLoadThriftRPCClient.java @@ -17,10 +17,7 @@ import org.apache.thrift.transport.TTransportException; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.*; import javax.servlet.Servlet; import java.net.URI; @@ -30,6 +27,7 @@ import java.util.stream.IntStream; /** * Created by vpankrashkin on 05.05.16. */ +@Ignore public class TestLoadThriftRPCClient { private Server server; @@ -46,7 +44,7 @@ public class TestLoadThriftRPCClient { serviceBuilder.withIdGenerator(new IdGeneratorStub()); serviceBuilder.withEventListener(new ServiceEventListener() { @Override - public void notifyEvent(ServiceEvent serviceEvent) { + public void notifyEvent(ServiceEvent event) { } }); @@ -88,7 +86,7 @@ public class TestLoadThriftRPCClient { e.printStackTrace(); } }); - int testCount = 10000; + int testCount = 20000; runHtriftRPC(testCount, tRPCClient); runThrift(testCount, tClient); System.out.println("Warmup ended."); diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ClientActionListener.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ClientActionListener.java new file mode 100644 index 0000000..1213354 --- /dev/null +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ClientActionListener.java @@ -0,0 +1,20 @@ +package com.rbkmoney.woody.thrift.impl.http.event; + +import com.rbkmoney.woody.api.event.ClientEvent; + +/** + * Created by vpankrashkin on 12.05.16. + */ +public interface ClientActionListener { + ClientEvent callService(ClientEvent event); + + ClientEvent clientSend(ClientEvent event); + + ClientEvent clientReceive(ClientEvent event); + + ClientEvent serviceResult(ClientEvent event); + + ClientEvent error(ClientEvent event); + + ClientEvent undefined(ClientEvent event); +} diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ClientEventListenerImpl.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ClientEventListenerImpl.java new file mode 100644 index 0000000..3425470 --- /dev/null +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ClientEventListenerImpl.java @@ -0,0 +1,52 @@ +package com.rbkmoney.woody.thrift.impl.http.event; + +import com.rbkmoney.woody.api.event.ClientEvent; +import com.rbkmoney.woody.api.event.ClientEventListener; + +/** + * Created by vpankrashkin on 12.05.16. + */ +public class ClientEventListenerImpl implements ClientEventListener { + private ClientActionListener eventActionListener; + + public ClientEventListenerImpl() { + } + + public ClientEventListenerImpl(ClientActionListener eventActionListener) { + this.eventActionListener = eventActionListener; + } + + public void setEventActionListener(ClientActionListener eventActionListener) { + this.eventActionListener = eventActionListener; + } + + @Override + public void notifyEvent(ClientEvent event) { + switch (event.getEventType()) { + case CALL_SERVICE: + if (eventActionListener != null) + eventActionListener.callService(event); + break; + case CLIENT_SEND: + if (eventActionListener != null) + eventActionListener.clientSend(event); + break; + case CLIENT_RECEIVE: + if (eventActionListener != null) + eventActionListener.clientReceive(event); + break; + case SERVICE_RESULT: + if (eventActionListener != null) + eventActionListener.serviceResult(event); + break; + case ERROR: + if (eventActionListener != null) + eventActionListener.error(event); + break; + default: + if (eventActionListener != null) + eventActionListener.undefined(event); + break; + } + } +} diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceActionListener.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceActionListener.java new file mode 100644 index 0000000..4a13c3b --- /dev/null +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceActionListener.java @@ -0,0 +1,20 @@ +package com.rbkmoney.woody.thrift.impl.http.event; + +import com.rbkmoney.woody.api.event.ServiceEvent; + +/** + * Created by vpankrashkin on 12.05.16. + */ +public interface ServiceActionListener { + ServiceEvent callHandler(ServiceEvent event); + + ServiceEvent handlerResult(ServiceEvent event); + + ServiceEvent serviceReceive(ServiceEvent event); + + ServiceEvent serviceResult(ServiceEvent event); + + ServiceEvent error(ServiceEvent event); + + ServiceEvent unddefined(ServiceEvent event); +} diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceEventListenerImpl.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceEventListenerImpl.java new file mode 100644 index 0000000..407e00e --- /dev/null +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceEventListenerImpl.java @@ -0,0 +1,53 @@ +package com.rbkmoney.woody.thrift.impl.http.event; + +import com.rbkmoney.woody.api.event.ServiceEvent; +import com.rbkmoney.woody.api.event.ServiceEventListener; + +/** + * Created by vpankrashkin on 12.05.16. + */ +public class ServiceEventListenerImpl implements ServiceEventListener { + private volatile ServiceActionListener eventActionListener; + + public ServiceEventListenerImpl() { + } + + public ServiceEventListenerImpl(ServiceActionListener eventActionListener) { + this.eventActionListener = eventActionListener; + } + + public void setEventActionListener(ServiceActionListener eventActionListener) { + this.eventActionListener = eventActionListener; + } + + @Override + public void notifyEvent(ServiceEvent event) { + switch (event.getEventType()) { + case CALL_HANDLER: + if (eventActionListener != null) + eventActionListener.callHandler(event); + break; + case HANDLER_RESULT: + if (eventActionListener != null) + eventActionListener.handlerResult(event); + break; + case SERVICE_RECEIVE: + if (eventActionListener != null) + eventActionListener.serviceReceive(event); + break; + case SERVICE_RESULT: + if (eventActionListener != null) + eventActionListener.serviceResult(event); + break; + case ERROR: + if (eventActionListener != null) + eventActionListener.error(event); + break; + default: + if (eventActionListener != null) + eventActionListener.unddefined(event); + break; + + } + } +} diff --git a/woody-thrift/src/test/resources/log4j.properties b/woody-thrift/src/test/resources/log4j.properties new file mode 100644 index 0000000..dd1c560 --- /dev/null +++ b/woody-thrift/src/test/resources/log4j.properties @@ -0,0 +1,5 @@ +log4j.rootLogger=INFO, stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p - %m%n From 62cf6ea16bef7867ead9fcf1873e8298a8b66c8c Mon Sep 17 00:00:00 2001 From: Vladimir Pankrashkin Date: Fri, 13 May 2016 11:05:04 +0300 Subject: [PATCH 4/5] MSPF-16: Pom fixes --- woody-thrift/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/woody-thrift/pom.xml b/woody-thrift/pom.xml index 200cf1c..fc06c60 100644 --- a/woody-thrift/pom.xml +++ b/woody-thrift/pom.xml @@ -35,9 +35,9 @@ ${api-version} - org.apache.thrift + com.rbkmoney.thrift libthrift - 0.9.3-woody_b0 + 0.9.3 org.slf4j From 327a69cb606329f657e2ccaa45c35a3a8c49e6ba Mon Sep 17 00:00:00 2001 From: Vladimir Pankrashkin Date: Tue, 17 May 2016 10:45:08 +0300 Subject: [PATCH 5/5] MSPF-16: Review fixes --- README.md | 2 +- .../api/interceptor/CompositeInterceptor.java | 4 -- .../api/proxy/HandleMethodCallerFactory.java | 35 +-------------- .../api/proxy/TestProxyInvocationFactory.java | 21 +-------- .../http/event/ClientEventLogListener.java | 4 +- .../http/event/ServiceEventLogListener.java | 44 ++++++++++--------- .../rbkmoney/woody/rpc/OwnerServiceImpl.java | 2 +- .../java/com/rbkmoney/woody/rpc/TestHttp.java | 5 +-- .../thrift/impl/http/OwnerServiceStub.java | 8 ++-- .../thrift/impl/http/TestChildRequests.java | 8 ++-- .../impl/http/TestClientEventHandling.java | 8 ++-- .../thrift/impl/http/TestEventOrder.java | 6 +-- .../impl/http/TestLoadErrThriftRPCClient.java | 16 +++---- .../src/test/thrift/testService.thrift | 6 +-- 14 files changed, 57 insertions(+), 112 deletions(-) diff --git a/README.md b/README.md index 5f0a1ef..1286591 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # com.rbkmoney.woody.rpc -Java реализация [Библиотеки RPC вызовов для общения между микросервисами](http://52.29.202.218/scrapyard/com.rbkmoney.woody.rpc-lib/). +Java реализация [Библиотеки RPC вызовов для общения между микросервисами](http://52.29.202.218/design/ms/platform/rpc-lib/). diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/CompositeInterceptor.java b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/CompositeInterceptor.java index 1f7a72e..22b493f 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/CompositeInterceptor.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/interceptor/CompositeInterceptor.java @@ -18,10 +18,6 @@ public class CompositeInterceptor implements CommonIn this(true, interceptors); } - /*public CompositeInterceptor(Collection interceptors) { - this(true, interceptors.stream().toArray(CommonInterceptor[]::new)); - }*/ - @Override public boolean interceptRequest(TraceData traceData, ReqProvider providerContext, Object... contextParams) { boolean successful = true; diff --git a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/HandleMethodCallerFactory.java b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/HandleMethodCallerFactory.java index 95a5827..706db4f 100644 --- a/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/HandleMethodCallerFactory.java +++ b/woody-api/src/main/java/com/rbkmoney/woody/api/proxy/HandleMethodCallerFactory.java @@ -22,13 +22,7 @@ public class HandleMethodCallerFactory implements MethodCallerFactory { @Override public Object call(Object[] args) throws Throwable { - return mh.invokeWithArguments(target, args) - ; - //.unreflectSpecial(method, target.getClass()) - - //.invokeWithArguments(args); - //.bindTo(target) - //.invokeWithArguments(args); + return mh.invokeWithArguments(target, args); } }; @@ -52,31 +46,4 @@ public class HandleMethodCallerFactory implements MethodCallerFactory { } } -// @Override -// public InstanceMethodCaller getInstance(Object target, Method method) { -// -// -// try { -// // 1. Retrieves a Lookup -// MethodHandles.Lookup lookup = MethodHandles.lookup(); -// -// MethodHandle handle=lookup.unreflect(method); -// -// -// // 4. Invoke the method -// return new InstanceMethodCaller() { -// @Override -// public Object call(Object[] args) throws Throwable { -// return handle.invokeWithArguments(args); -// } -// }; -// //return args -> handle.invokeWithArguments(args); -// // ^----^ ^----^ -// // | argument -// // instance of FooBar to invoke the method on -// }catch ( IllegalAccessException e) { -// e.printStackTrace(); -// throw new RuntimeException(e); -// } -// } } diff --git a/woody-api/src/test/java/com/rbkmoney/woody/api/proxy/TestProxyInvocationFactory.java b/woody-api/src/test/java/com/rbkmoney/woody/api/proxy/TestProxyInvocationFactory.java index 447497c..2d8ea1e 100644 --- a/woody-api/src/test/java/com/rbkmoney/woody/api/proxy/TestProxyInvocationFactory.java +++ b/woody-api/src/test/java/com/rbkmoney/woody/api/proxy/TestProxyInvocationFactory.java @@ -1,6 +1,7 @@ package com.rbkmoney.woody.api.proxy; import com.rbkmoney.woody.api.trace.context.EventTracer; +import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.assertSame; @@ -8,34 +9,16 @@ import static org.junit.Assert.assertSame; /** * Created by vpankrashkin on 23.04.16. */ +@Ignore public class TestProxyInvocationFactory { @Test public void testString() { - //Srv direct = () -> "test"; Srv directImpl = new Srv() { - @Override public String getString() { return "string"; } }; - MethodCallTracer callTracer = new MethodCallTracer() { - @Override - public void beforeCall(Object[] args, InstanceMethodCaller caller) { - //System.out.println("Before"); - } - - @Override - public void afterCall(Object[] args, InstanceMethodCaller caller, Object result) { - //System.out.println("After"); - } - - @Override - public void callError(Object[] args, InstanceMethodCaller caller, Throwable error) { - //System.out.println("Error:" + error); - error.printStackTrace(); - } - }; MethodCallTracer wrappedCallTracer = new EventTracer(); diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ClientEventLogListener.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ClientEventLogListener.java index 0c016e7..10917f6 100644 --- a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ClientEventLogListener.java +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ClientEventLogListener.java @@ -13,8 +13,8 @@ public class ClientEventLogListener implements ClientEventListener { @Override public void notifyEvent(ClientEvent event1) { - THClientEvent event = (THClientEvent) event1; try { + THClientEvent event = (THClientEvent) event1; switch (event.getEventType()) { case CALL_SERVICE: log.info("CLIENT Event: {}, Span [{}-{}-{}], [{}, Type: {}], Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.getCallName(), event.getCallType(), event.getTimeStamp()); @@ -36,7 +36,7 @@ public class ClientEventLogListener implements ClientEventListener { break; } } catch (Exception e) { - + log.error("Event processing failed", e); } } } diff --git a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceEventLogListener.java b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceEventLogListener.java index 46a77e8..546d64b 100644 --- a/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceEventLogListener.java +++ b/woody-thrift/src/main/java/com/rbkmoney/woody/thrift/impl/http/event/ServiceEventLogListener.java @@ -13,27 +13,31 @@ public class ServiceEventLogListener implements ServiceEventListener { @Override public void notifyEvent(ServiceEvent event1) { - THServiceEvent event = (THServiceEvent) event1; - switch (event.getEventType()) { - case CALL_HANDLER: - log.info("SERVER Event: {}, Span [{}-{}-{}], [{}, Type: {}], Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.getCallName(), event.getCallType(), event.getTimeStamp()); - break; - case HANDLER_RESULT: - log.info("SERVER Event: {}, Span [{}-{}-{}], Status: {}, Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.isSuccessfullCall() ? "ok" : "error", event.getTimeStamp()); - break; - case SERVICE_RECEIVE: - log.info("SERVER Event: {}, Span [{}-{}-{}], Status: {}, Url: {}, Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.isSuccessfullCall() ? "ok" : "error", event.getEndpoint().getStringValue(), event.getTimeStamp()); - break; - case SERVICE_RESULT: - log.info("SERVER Event: {}, Span [{}-{}-{}], Status: {}, Time: {}, Duration: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.isSuccessfullCall() ? "ok" : "error", event.getTimeStamp(), event.getDuration()); - break; - case ERROR: - log.info("SERVER Event: {}, Span [{}-{}-{}], ErrType: {}, TErrType: {}, ErrName: {}, Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.getErrorType(), event.getThriftErrorType(), event.getErrorName(), event.getTimeStamp()); - break; - default: - log.info("SERVER Unknown error: {}", event); - break; + try { + THServiceEvent event = (THServiceEvent) event1; + switch (event.getEventType()) { + case CALL_HANDLER: + log.info("SERVER Event: {}, Span [{}-{}-{}], [{}, Type: {}], Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.getCallName(), event.getCallType(), event.getTimeStamp()); + break; + case HANDLER_RESULT: + log.info("SERVER Event: {}, Span [{}-{}-{}], Status: {}, Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.isSuccessfullCall() ? "ok" : "error", event.getTimeStamp()); + break; + case SERVICE_RECEIVE: + log.info("SERVER Event: {}, Span [{}-{}-{}], Status: {}, Url: {}, Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.isSuccessfullCall() ? "ok" : "error", event.getEndpoint().getStringValue(), event.getTimeStamp()); + break; + case SERVICE_RESULT: + log.info("SERVER Event: {}, Span [{}-{}-{}], Status: {}, Time: {}, Duration: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.isSuccessfullCall() ? "ok" : "error", event.getTimeStamp(), event.getDuration()); + break; + case ERROR: + log.info("SERVER Event: {}, Span [{}-{}-{}], ErrType: {}, TErrType: {}, ErrName: {}, Time: {}", event.getEventType(), event.getTraceId(), event.getSpanId(), event.getParentId(), event.getErrorType(), event.getThriftErrorType(), event.getErrorName(), event.getTimeStamp()); + break; + default: + log.info("SERVER Unknown error: {}", event); + break; + } + } catch (Exception e) { + log.error("Failed to process event", e); } } diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/OwnerServiceImpl.java b/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/OwnerServiceImpl.java index 125bb4a..a6b462f 100644 --- a/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/OwnerServiceImpl.java +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/OwnerServiceImpl.java @@ -12,7 +12,7 @@ public class OwnerServiceImpl implements OwnerService.Iface { } @Override - public Owner getErrOwner(int id) throws err_one, TException { + public Owner getErrOwner(int id) throws test_error, TException { return null; } diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/TestHttp.java b/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/TestHttp.java index f3b1385..797ce90 100644 --- a/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/TestHttp.java +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/rpc/TestHttp.java @@ -9,7 +9,6 @@ import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.server.TServlet; import org.apache.thrift.transport.THttpClient; -import org.apache.thrift.transport.TTransportException; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; @@ -29,8 +28,6 @@ public class TestHttp { server = new Server(8080); ServletContextHandler context = new ServletContextHandler(); ServletHolder defaultServ = new ServletHolder("default", TServletExample.class); - //defaultServ.setInitParameter("resourceBase",System.getProperty("user.dir")); - //defaultServ.setInitParameter("dirAllowed","true"); context.addServlet(defaultServ, "/"); server.setHandler(context); @@ -48,7 +45,7 @@ public class TestHttp { } @Test - public void testServlet() throws TTransportException, TException { + public void testServlet() throws TException { String servletUrl = "http://localhost:8080/"; THttpClient thc = new THttpClient(servletUrl); TProtocol loPFactory = new TCompactProtocol(thc); diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/OwnerServiceStub.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/OwnerServiceStub.java index 0333865..82e80b2 100644 --- a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/OwnerServiceStub.java +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/OwnerServiceStub.java @@ -2,7 +2,7 @@ package com.rbkmoney.woody.thrift.impl.http; import com.rbkmoney.woody.rpc.Owner; import com.rbkmoney.woody.rpc.OwnerService; -import com.rbkmoney.woody.rpc.err_one; +import com.rbkmoney.woody.rpc.test_error; import org.apache.thrift.TException; /** @@ -15,8 +15,8 @@ public class OwnerServiceStub implements OwnerService.Iface { } @Override - public Owner getErrOwner(int id) throws err_one, TException { - throw new err_one(id); + public Owner getErrOwner(int id) throws test_error, TException { + throw new test_error(id); } @Override @@ -31,6 +31,6 @@ public class OwnerServiceStub implements OwnerService.Iface { @Override public Owner setErrOwner(Owner owner, int id) throws TException { - throw new err_one(id); + throw new test_error(id); } } diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestChildRequests.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestChildRequests.java index 550336c..e561d0d 100644 --- a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestChildRequests.java +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestChildRequests.java @@ -2,7 +2,7 @@ package com.rbkmoney.woody.thrift.impl.http; import com.rbkmoney.woody.rpc.Owner; import com.rbkmoney.woody.rpc.OwnerService; -import com.rbkmoney.woody.rpc.err_one; +import com.rbkmoney.woody.rpc.test_error; import com.rbkmoney.woody.thrift.impl.http.event.ClientEventListenerImpl; import com.rbkmoney.woody.thrift.impl.http.event.ClientEventLogListener; import com.rbkmoney.woody.thrift.impl.http.event.ServiceEventListenerImpl; @@ -31,14 +31,14 @@ public class TestChildRequests extends AbstractTest { OwnerService.Iface client2 = createThriftRPCClient(OwnerService.Iface.class, new IdGeneratorStub(), new ClientEventLogListener(), getUrlString("/rpc")); OwnerService.Iface handler = new OwnerServiceStub() { @Override - public Owner getErrOwner(int id) throws TException, err_one { + public Owner getErrOwner(int id) throws TException, test_error { switch (id) { case 0: Owner owner = client2.getOwner(0); client2.setOwnerOneway(owner); return client2.getOwner(10); case 200: - throw new err_one(200); + throw new test_error(200); case 500: throw new RuntimeException("Test"); default: @@ -64,7 +64,7 @@ public class TestChildRequests extends AbstractTest { try { client1.getErrOwner(200); Assert.fail(); - } catch (err_one e) { + } catch (test_error e) { } out.println("<"); out.println("Root call>"); diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestClientEventHandling.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestClientEventHandling.java index 73c3d3f..5949fa4 100644 --- a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestClientEventHandling.java +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestClientEventHandling.java @@ -6,7 +6,7 @@ import com.rbkmoney.woody.api.event.ErrorType; import com.rbkmoney.woody.api.generator.IdGenerator; import com.rbkmoney.woody.rpc.Owner; import com.rbkmoney.woody.rpc.OwnerService; -import com.rbkmoney.woody.rpc.err_one; +import com.rbkmoney.woody.rpc.test_error; import com.rbkmoney.woody.thrift.impl.http.event.THClientEvent; import org.apache.thrift.TException; import org.junit.Test; @@ -33,8 +33,8 @@ public class TestClientEventHandling extends AbstractTest { } @Override - public Owner getErrOwner(int id) throws err_one { - throw new err_one(id); + public Owner getErrOwner(int id) throws test_error { + throw new test_error(id); } } @@ -71,7 +71,7 @@ public class TestClientEventHandling extends AbstractTest { case ERROR: assertFalse(thClientEvent.isSuccessfullCall()); assertEquals(ErrorType.APPLICATION_KNOWN_ERROR, thClientEvent.getErrorType()); - assertEquals("err_one", thClientEvent.getErrorName()); + assertEquals("test_error", thClientEvent.getErrorName()); assertNull(thClientEvent.getThriftErrorType()); break; default: diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestEventOrder.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestEventOrder.java index eefe3ce..c717b5b 100644 --- a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestEventOrder.java +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestEventOrder.java @@ -2,7 +2,7 @@ package com.rbkmoney.woody.thrift.impl.http; import com.rbkmoney.woody.rpc.Owner; import com.rbkmoney.woody.rpc.OwnerService; -import com.rbkmoney.woody.rpc.err_one; +import com.rbkmoney.woody.rpc.test_error; import com.rbkmoney.woody.thrift.impl.http.event.ClientActionListener; import com.rbkmoney.woody.thrift.impl.http.event.ClientEventListenerImpl; import com.rbkmoney.woody.thrift.impl.http.event.ServiceActionListener; @@ -25,7 +25,7 @@ public class TestEventOrder extends AbstractTest { ServiceEventListenerImpl serviceEventListener = new ServiceEventListenerImpl(); OwnerService.Iface handler = new OwnerServiceStub() { @Override - public Owner getErrOwner(int id) throws TException, err_one { + public Owner getErrOwner(int id) throws TException, test_error { switch (id) { case 500: throw new RuntimeException("Test"); @@ -117,7 +117,7 @@ public class TestEventOrder extends AbstractTest { try { client.getErrOwner(1); Assert.fail("Exception should be here"); - } catch (err_one e) { + } catch (test_error e) { Assert.assertEquals(1, e.getId()); } diff --git a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestLoadErrThriftRPCClient.java b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestLoadErrThriftRPCClient.java index eb4b526..dcd16fe 100644 --- a/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestLoadErrThriftRPCClient.java +++ b/woody-thrift/src/test/java/com/rbkmoney/woody/thrift/impl/http/TestLoadErrThriftRPCClient.java @@ -3,7 +3,7 @@ package com.rbkmoney.woody.thrift.impl.http; import com.rbkmoney.woody.api.generator.IdGenerator; import com.rbkmoney.woody.rpc.Owner; import com.rbkmoney.woody.rpc.OwnerService; -import com.rbkmoney.woody.rpc.err_one; +import com.rbkmoney.woody.rpc.test_error; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.thrift.TException; import org.apache.thrift.protocol.TCompactProtocol; @@ -34,8 +34,6 @@ public class TestLoadErrThriftRPCClient { server = new Server(8080); ServletContextHandler context = new ServletContextHandler(); ServletHolder defaultServ = new ServletHolder("default", TServletExample.class); - //defaultServ.setInitParameter("resourceBase",System.getProperty("user.dir")); - //defaultServ.setInitParameter("dirAllowed","true"); context.addServlet(defaultServ, "/"); server.setHandler(context); @@ -61,14 +59,14 @@ public class TestLoadErrThriftRPCClient { try { tClient.getErrOwner(0); } catch (TException e) { - Assert.assertSame(e.getClass(), err_one.class); + Assert.assertSame(e.getClass(), test_error.class); //e.printStackTrace(); } try { tRPCClient.getErrOwner(0); } catch (TException e) { - Assert.assertSame(e.getClass(), err_one.class); + Assert.assertSame(e.getClass(), test_error.class); //e.printStackTrace(); } @@ -92,7 +90,7 @@ public class TestLoadErrThriftRPCClient { IntStream.range(1, testCount).forEach(i -> { try { tClient.getErrOwner(i); - } catch (err_one e) { + } catch (test_error e) { } catch (Exception e) { e.printStackTrace(); @@ -107,7 +105,7 @@ public class TestLoadErrThriftRPCClient { IntStream.range(1, testCount).forEach(i -> { try { tRPCClient.getErrOwner(i); - } catch (err_one e) { + } catch (test_error e) { } catch (Exception e) { e.printStackTrace(); @@ -153,8 +151,8 @@ public class TestLoadErrThriftRPCClient { private static class OwnerServiceImpl extends OwnerServiceStub { @Override - public Owner getErrOwner(int id) throws TException, err_one { - throw new err_one(id); + public Owner getErrOwner(int id) throws TException, test_error { + throw new test_error(id); } } diff --git a/woody-thrift/src/test/thrift/testService.thrift b/woody-thrift/src/test/thrift/testService.thrift index aa9d875..96afdec 100644 --- a/woody-thrift/src/test/thrift/testService.thrift +++ b/woody-thrift/src/test/thrift/testService.thrift @@ -6,15 +6,15 @@ struct Owner { 2:string name } -exception err_one { +exception test_error { 1:int id } service OwnerService { Owner getOwner(1:int id), - Owner getErrOwner(1:int id) throws (1:err_one err), + Owner getErrOwner(1:int id) throws (1:test_error err), void setOwner(1:Owner owner), oneway void setOwnerOneway(1:Owner owner) - Owner setErrOwner(1:Owner owner, 2:int id) throws (1:err_one err) + Owner setErrOwner(1:Owner owner, 2:int id) throws (1:test_error err) } \ No newline at end of file