/*
* Copyright 2012-2015, the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.flipkart.phantom.task.impl.repository;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import com.flipkart.phantom.task.impl.collector.EventDispatchingSpanCollector;
import com.flipkart.phantom.task.impl.interceptor.AbstractClientResponseInterceptor;
import com.flipkart.phantom.task.impl.interceptor.ClientRequestInterceptor;
import com.flipkart.phantom.task.spi.AbstractHandler;
import com.flipkart.phantom.task.spi.Executor;
import com.flipkart.phantom.task.spi.RequestContext;
import com.flipkart.phantom.task.spi.RequestWrapper;
import com.flipkart.phantom.task.spi.TaskContext;
import com.flipkart.phantom.task.spi.interceptor.RequestInterceptor;
import com.flipkart.phantom.task.spi.interceptor.ResponseInterceptor;
import com.flipkart.phantom.task.spi.registry.AbstractHandlerRegistry;
import com.flipkart.phantom.task.spi.repository.ExecutorRepository;
import com.github.kristofa.brave.TraceFilter;
import com.google.common.base.Optional;
/**
* <code>AbstractExecutorRepository</code> is an implementation of {@link ExecutorRepository} that hs data and behavior to all protocol specific sub-types.
*
* @author Regunath B
* @version 1.0, 24th Nov, 2014
*/
public abstract class AbstractExecutorRepository<T extends RequestWrapper,S, R extends AbstractHandler> implements ExecutorRepository<T,S,R>, InitializingBean {
/** The registry holding the names of the TaskHandler */
protected AbstractHandlerRegistry<R> registry;
/** The taskContext being passed to the Handlers, providing a way for communication to the Container */
protected TaskContext taskContext;
/** The client request and response interceptors*/
protected List<RequestInterceptor<T>> requestInterceptors = new LinkedList<RequestInterceptor<T>>();
protected List<ResponseInterceptor<S>> responseInterceptors = new LinkedList<ResponseInterceptor<S>>();
/** The EventDispatchingSpanCollector instance used in tracing requests*/
protected EventDispatchingSpanCollector eventDispatchingSpanCollector;
/**
* Interface method implementation. Checks if all mandatory properties have been set
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.registry, "The 'registry' may not be null");
Assert.notNull(this.taskContext, "The 'taskContext' may not be null");
Assert.notNull(this.eventDispatchingSpanCollector, "The 'eventDispatchingSpanCollector' may not be null");
}
/**
* Helper method to wrap the Executor with request and response interceptors
*/
protected Executor<T,S> wrapExecutorWithInterceptors(Executor<T,S> executor, R handler,
ClientRequestInterceptor<T> tracingRequestInterceptor, AbstractClientResponseInterceptor<S> tracingResponseInterceptor) {
if (executor != null) {
// we'll add the request and response interceptors that were configured on this repository
for (RequestInterceptor<T> requestInterceptor : this.requestInterceptors) {
executor.addRequestInterceptor(requestInterceptor);
}
for (ResponseInterceptor<S> responseInterceptor : this.responseInterceptors) {
executor.addResponseInterceptor(responseInterceptor);
}
// now add the tracing interceptors - has to be an instance specific to each new Executor
Optional<RequestContext> requestContextOptional = executor.getRequestWrapper().getRequestContext();
List<TraceFilter> traceFilters = Arrays.<TraceFilter>asList(this.registry.getTraceFilterForHandler(handler.getName()));
// The request did not come through a server/service call i.e. not via Netty Channel handlers
if (!requestContextOptional.isPresent()) {
RequestContext newRequestContext = new RequestContext();
requestContextOptional = Optional.of(newRequestContext);
executor.getRequestWrapper().setRequestContext(requestContextOptional);
}
if (requestContextOptional.get().getCurrentServerSpan() != null) { // dont wrap the tracing interceptors if trace is not on
final String serviceName = executor.getServiceName().isPresent() ? executor.getServiceName().get() : Executor.DEFAULT_SERVICE_NAME;
// Set the client endpoint on the request context
requestContextOptional.get().setCurrentClientEndpoint(new RequestContext.ServiceEndpoint(handler.getHost(), handler.getPort(), serviceName));
tracingRequestInterceptor.setEventDispatchingSpanCollector(this.eventDispatchingSpanCollector);
tracingRequestInterceptor.setTraceFilters(traceFilters);
executor.addRequestInterceptor(tracingRequestInterceptor);
tracingResponseInterceptor.setEventDispatchingSpanCollector(this.eventDispatchingSpanCollector);
tracingResponseInterceptor.setTraceFilters(traceFilters);
executor.addResponseInterceptor(tracingResponseInterceptor);
}
}
return executor;
}
/** Getter/Setter methods */
public AbstractHandlerRegistry<R> getRegistry() {
return registry;
}
public void setRegistry(AbstractHandlerRegistry<R> registry) {
this.registry = registry;
}
public TaskContext getTaskContext() {
return this.taskContext;
}
public void setTaskContext(TaskContext taskContext) {
this.taskContext = taskContext;
}
public void setRequestInterceptors(List<RequestInterceptor<T>> requestInterceptors) {
this.requestInterceptors = requestInterceptors;
}
public void setResponseInterceptors(List<ResponseInterceptor<S>> responseInterceptors) {
this.responseInterceptors = responseInterceptors;
}
public void setEventDispatchingSpanCollector(EventDispatchingSpanCollector eventDispatchingSpanCollector) {
this.eventDispatchingSpanCollector = eventDispatchingSpanCollector;
}
/** End Getter/Setter methods */
}