package com.linkedin.r2.filter.message.stream; import com.linkedin.common.callback.Callback; import com.linkedin.r2.filter.NextFilter; import com.linkedin.r2.filter.message.rest.RestFilter; import com.linkedin.r2.message.RequestContext; import com.linkedin.r2.message.Messages; import com.linkedin.r2.message.Request; import com.linkedin.r2.message.Response; import com.linkedin.r2.message.rest.RestException; import com.linkedin.r2.message.rest.RestRequest; import com.linkedin.r2.message.rest.RestResponse; import com.linkedin.r2.message.stream.StreamException; import com.linkedin.r2.message.stream.StreamRequest; import com.linkedin.r2.message.stream.StreamResponse; import java.util.Map; /** * This helper class provides methods to adapt RestFilters to StreamFilters as currently FilterChain would ignore * RestFilters. * * However, using RestFilters would cause the request and/or response being fully buffered in memory, negating the * benefits brought by R2 streaming. * * This class is only supposed to be used during transition period where both rest & stream code path for filter * chain exist. Avoid use it if possible. * * @author Zhenkai Zhu */ public class StreamFilterAdapters { private StreamFilterAdapters() {} public static StreamFilter adaptRestFilter(RestFilter filter) { return new StreamFilterAdapter(filter); } private static class StreamFilterAdapter implements StreamFilter { RestFilter _filter; public StreamFilterAdapter(RestFilter filter) { _filter = filter; } @Override public void onStreamRequest(StreamRequest req, final RequestContext requestContext, final Map<String, String> wireAttrs, final NextFilter<StreamRequest, StreamResponse> nextFilter) { Messages.toRestRequest(req, new Callback<RestRequest>() { @Override public void onError(Throwable e) { nextFilter.onError(e, requestContext, wireAttrs); } @Override public void onSuccess(RestRequest result) { _filter.onRestRequest(result, requestContext, wireAttrs, new AdaptingNextFilter(nextFilter)); } }); } @Override public void onStreamResponse(StreamResponse res, final RequestContext requestContext, final Map<String, String> wireAttrs, final NextFilter<StreamRequest, StreamResponse> nextFilter) { Messages.toRestResponse(res, new Callback<RestResponse>() { @Override public void onError(Throwable e) { nextFilter.onError(e, requestContext, wireAttrs); } @Override public void onSuccess(RestResponse result) { _filter.onRestResponse(result, requestContext, wireAttrs, new AdaptingNextFilter(nextFilter)); } }); } @Override public void onStreamError(Throwable ex, final RequestContext requestContext, final Map<String, String> wireAttrs, final NextFilter<StreamRequest, StreamResponse> nextFilter) { if (ex instanceof StreamException) { Messages.toRestException((StreamException)ex, new Callback<RestException>() { @Override public void onError(Throwable e) { nextFilter.onError(e, requestContext, wireAttrs); } @Override public void onSuccess(RestException result) { _filter.onRestError(result, requestContext, wireAttrs, new AdaptingNextFilter(nextFilter)); } }); } else { _filter.onRestError(ex, requestContext, wireAttrs, new AdaptingNextFilter(nextFilter)); } } } private static class AdaptingNextFilter implements NextFilter<RestRequest, RestResponse> { private final NextFilter<StreamRequest, StreamResponse> _nextFilter; AdaptingNextFilter(NextFilter<StreamRequest, StreamResponse> nextFilter) { _nextFilter = nextFilter; } public void onRequest(RestRequest req, RequestContext requestContext, Map<String, String> wireAttrs) { StreamRequest streamRequest = Messages.toStreamRequest(req); _nextFilter.onRequest(streamRequest, requestContext, wireAttrs); } public void onResponse(RestResponse res, RequestContext requestContext, Map<String, String> wireAttrs) { StreamResponse streamResponse = Messages.toStreamResponse(res); _nextFilter.onResponse(streamResponse, requestContext, wireAttrs); } public void onError(Throwable ex, RequestContext requestContext, Map<String, String> wireAttrs) { if (ex instanceof RestException) { StreamException streamException = Messages.toStreamException((RestException)ex); _nextFilter.onError(streamException, requestContext, wireAttrs); } else { _nextFilter.onError(ex, requestContext, wireAttrs); } } } }