mirror of
https://github.com/valitydev/woody_java.git
synced 2024-11-06 08:15:21 +00:00
MSPF-16: Client and server part
This commit is contained in:
parent
d3bb9f1f73
commit
d97847f4e4
@ -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/).
|
||||
|
3
pom.xml
3
pom.xml
@ -8,6 +8,9 @@
|
||||
<artifactId>woody</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<description>Java implementation for Woody spec</description>
|
||||
<properties>
|
||||
<api-version>1.0.0</api-version>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>woody-api</module>
|
||||
|
@ -10,6 +10,8 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>woody-api</artifactId>
|
||||
<version>${api-version}</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
@ -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> T build(Class<T> clientInterface) {
|
||||
return createProxyClient(clientInterface, null);
|
||||
protected URI getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
protected ClientEventListener getEventListener() {
|
||||
return eventListener;
|
||||
}
|
||||
|
||||
protected IdGenerator getIdGenerator() {
|
||||
return idGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T build(Class<T> clientInterface, ClientProviderControl providerControl) {
|
||||
T target = null;
|
||||
return createProxyClient(clientInterface, target);
|
||||
public <T> T build(Class<T> clientInterface) {
|
||||
try {
|
||||
T target = createProviderClient(clientInterface);
|
||||
return createProxyClient(clientInterface, target);
|
||||
} catch (Exception e) {
|
||||
throw new WoodyInstantiationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> T createProxyClient(Class<T> 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> T createProxyTarget(Class<T> 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> T createProviderClient(Class<T> 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> T build(Class<T> 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;
|
||||
}
|
||||
|
@ -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<Service> implements ServiceBuilder<Service> {
|
||||
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 <T> Service build(Class<T> 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 <T> Service createProviderService(Class<T> serviceInterface, T handler);
|
||||
|
||||
|
||||
protected <T> T createProxyService(Class<T> 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> T build(Class<T> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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> T build(Class<T> clientInterface);
|
||||
|
||||
<T> T build(Class<T> clientInterface, ClientProviderControl configurator);
|
||||
}
|
||||
|
@ -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<Service> {
|
||||
ServiceBuilder withEventListener(ServiceEventListener listener);
|
||||
|
||||
ServiceBuilder withIdGenerator(IdGenerator generator);
|
||||
|
||||
<T> T build(Class<T> serviceInterface);
|
||||
|
||||
<T> T build(Class<T> serviceInterface, ServiceConfigurator configurator);
|
||||
<T> Service build(Class<T> serviceInterface, T serviceHandler);
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
package com.rbkmoney.woody.api;
|
||||
|
||||
/**
|
||||
* Created by vpankrashkin on 22.04.16.
|
||||
*/
|
||||
public interface ServiceConfigurator<T> {
|
||||
void configure(T serviceProvider);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.rbkmoney.woody.api.event;
|
||||
|
||||
/**
|
||||
* Created by vpankrashkin on 05.05.16.
|
||||
*/
|
||||
public enum CallType {
|
||||
CALL,
|
||||
CAST
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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<ClientEventType, ErrorType> {
|
||||
void notifyEvent(ClientEventType eventType, TraceData traceData);
|
||||
public interface ClientEventListener extends EventListener<ClientEvent> {
|
||||
void notifyEvent(ClientEvent event);
|
||||
|
||||
void notifyError(ErrorType errorType, TraceData traceData);
|
||||
}
|
||||
|
@ -2,9 +2,28 @@ package com.rbkmoney.woody.api.event;
|
||||
|
||||
/**
|
||||
* Created by vpankrashkin on 22.04.16.
|
||||
* <p>
|
||||
* 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
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
@ -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<EvnT, ErrT> {
|
||||
void notifyEvent(EvnT eventType, TraceData traceData);
|
||||
|
||||
void notifyError(ErrT errorType, TraceData traceData);
|
||||
public interface EventListener<E extends Event> {
|
||||
void notifyEvent(E event);
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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<ServiceEventType, ErrorType> {
|
||||
void notifyEvent(ServiceEventType eventType, TraceData traceData);
|
||||
|
||||
void notifyError(ErrorType errorType, TraceData traceData);
|
||||
public interface ServiceEventListener extends EventListener<ServiceEvent> {
|
||||
void notifyEvent(ServiceEvent serviceEvent);
|
||||
}
|
||||
|
@ -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<ReqProvider, RespProvider> implements CommonInterceptor<ReqProvider, RespProvider> {
|
||||
private RequestInterceptor<ReqProvider> requestInterceptor;
|
||||
private ResponseInterceptor<RespProvider> responseInterceptor;
|
||||
|
||||
public BasicCommonInterceptor(RequestInterceptor<ReqProvider> requestInterceptor, ResponseInterceptor<RespProvider> 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);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.rbkmoney.woody.api.interceptor;
|
||||
|
||||
/**
|
||||
* Created by vpankrashkin on 28.04.16.
|
||||
*/
|
||||
public interface CommonInterceptor<ReqProvider, RespProvider> extends RequestInterceptor<ReqProvider>, ResponseInterceptor<RespProvider> {
|
||||
}
|
@ -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<ReqProvider, RespProvider> implements CommonInterceptor<ReqProvider, RespProvider> {
|
||||
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<? extends CommonInterceptor> 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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<ReqProvider, RespProvider> implements CommonInterceptor<ReqProvider, RespProvider> {
|
||||
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;
|
||||
}
|
||||
}
|
@ -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<ReqProvider, RespProvider> implements CommonInterceptor<ReqProvider, RespProvider> {
|
||||
|
||||
@Override
|
||||
public boolean interceptRequest(TraceData traceData, ReqProvider providerContext, Object... contextParams) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interceptResponse(TraceData traceData, RespProvider providerContext, Object... contextParams) {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -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<Provider> {
|
||||
/**
|
||||
* @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);
|
||||
}
|
@ -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<Provider> {
|
||||
/**
|
||||
* @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);
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package com.rbkmoney.woody.api.provider;
|
||||
|
||||
/**
|
||||
* Created by vpankrashkin on 22.04.16.
|
||||
*/
|
||||
public interface ClientProviderControl<T> {
|
||||
void configure(T clientProvider);
|
||||
}
|
@ -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<ReqProvider, RespProvider> implements CommonInterceptor<ReqProvider, RespProvider> {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@ -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 {
|
||||
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -9,4 +9,5 @@ public interface MethodCallTracer {
|
||||
void afterCall(Object[] args, InstanceMethodCaller caller, Object result);
|
||||
|
||||
void callError(Object[] args, InstanceMethodCaller caller, Throwable error);
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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> T createErrIfNotIntercepted(ContextSpan span, Function<Throwable, T> 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> T getMetadataParameter(ContextSpan span, Class<T> 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> T getContextParameter(Class<T> 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;
|
||||
}
|
||||
}
|
@ -3,8 +3,8 @@ package com.rbkmoney.woody.api.trace;
|
||||
/**
|
||||
* Created by vpankrashkin on 21.04.16.
|
||||
*/
|
||||
public interface Endpoint<S, T> {
|
||||
S getSource();
|
||||
public interface Endpoint<T> {
|
||||
String getStringValue();
|
||||
|
||||
T getTarget();
|
||||
T getValue();
|
||||
}
|
||||
|
@ -25,6 +25,10 @@ public class Metadata {
|
||||
return (T) values.put(key, value);
|
||||
}
|
||||
|
||||
public boolean containsKey(String key) {
|
||||
return values.containsKey(key);
|
||||
}
|
||||
|
||||
public Collection<String> getKeys() {
|
||||
return values.keySet();
|
||||
}
|
||||
|
@ -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";
|
||||
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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<? extends MethodCallTracer> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
@ -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<ReqProvider, RespProvider> implements CommonInterceptor<ReqProvider, RespProvider> {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@ -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<Transport> extends RequestInterceptor<ClientSpan, Transport> {
|
||||
}
|
@ -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<Transport> extends ResponseInterceptor<ServerSpan, Transport> {
|
||||
}
|
@ -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<Context extends AbstractSpan, Transport> {
|
||||
boolean interceptRequest(Context context, Transport spanContext);
|
||||
}
|
@ -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<Context extends AbstractSpan, Transport> {
|
||||
void interceptResponse(Context context, Transport transport);
|
||||
}
|
@ -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<Transport> extends RequestInterceptor<ServerSpan, Transport> {
|
||||
}
|
@ -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<Transport> extends ResponseInterceptor<ServerSpan, Transport> {
|
||||
}
|
@ -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<Context extends AbstractSpan, Transport> implements RequestInterceptor<Context, Transport> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -11,5 +11,70 @@
|
||||
|
||||
<artifactId>woody-thrift</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-quickstart</artifactId>
|
||||
<version>9.3.9.M1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.rbkmoney.woody</groupId>
|
||||
<artifactId>woody-api</artifactId>
|
||||
<version>${api-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.thrift</groupId>
|
||||
<artifactId>libthrift</artifactId>
|
||||
<version>0.9.3-woody_b0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.thrift</groupId>
|
||||
<artifactId>thrift-maven-plugin</artifactId>
|
||||
<version>1.0-forked</version>
|
||||
<configuration>
|
||||
<thriftExecutable>/usr/local/bin/thrift</thriftExecutable>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>thrift-sources</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>thrift-test-sources</id>
|
||||
<phase>generate-test-sources</phase>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<finalName>rpc-lib</finalName>
|
||||
</build>
|
||||
</project>
|
@ -1,24 +0,0 @@
|
||||
package com.rbkmoney.woody.thrift;
|
||||
|
||||
/**
|
||||
* Created by vpankrashkin on 22.04.16.
|
||||
* <p>
|
||||
* 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
|
||||
|
||||
}
|
@ -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
|
||||
}
|
@ -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> T createProviderClient(Class<T> 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> T createThriftClient(Class<T> clientIface, TProtocol tProtocol, CommonInterceptor interceptor) {
|
||||
try {
|
||||
Optional<? extends Class> 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()));
|
||||
}
|
||||
}
|
@ -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<Method, Class[]> 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<ContextSpan, ContextSpan> 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<Method, Class[]> getDeclaredErrorsMap(Class iface) {
|
||||
Map<Method, Class[]> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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";
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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<Servlet> {
|
||||
|
||||
|
||||
@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 <T> Servlet createProviderService(Class<T> 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 <T> TProcessor createThriftProcessor(Class<T> serviceInterface, T handler) {
|
||||
try {
|
||||
Optional<? extends Class> 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()));
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<TMessage> {
|
||||
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;
|
||||
}
|
||||
}
|
@ -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<TMessage> {
|
||||
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;
|
||||
}
|
||||
}
|
@ -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<String[]> 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<String[]> 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<String[]> prepareClientHeaders(ClientSpan clientSpan) {
|
||||
Span span = clientSpan.getSpan();
|
||||
ArrayList<String[]> 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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<TMessage> {
|
||||
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;
|
||||
}
|
||||
}
|
@ -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<TMessage> {
|
||||
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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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<HttpServletResponse> {
|
||||
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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
|
||||
}
|
@ -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<String> {
|
||||
private String url;
|
||||
|
||||
public UrlStringEndpoint(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStringValue() {
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return url;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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<I> {
|
||||
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> T createThriftClient(Class<T> 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> T createThriftRPCClient(Class<T> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
6
woody-thrift/src/test/resources/jetty-logging.properties
Normal file
6
woody-thrift/src/test/resources/jetty-logging.properties
Normal file
@ -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
|
20
woody-thrift/src/test/thrift/testService.thrift
Normal file
20
woody-thrift/src/test/thrift/testService.thrift
Normal file
@ -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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user