package com.dianping.pigeon.remoting.invoker;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import com.dianping.pigeon.log.Logger;
import com.dianping.pigeon.log.LoggerLoader;
import com.dianping.pigeon.remoting.common.domain.InvocationRequest;
import com.dianping.pigeon.remoting.common.domain.InvocationResponse;
import com.dianping.pigeon.remoting.common.exception.NetworkException;
import com.dianping.pigeon.remoting.common.util.Constants;
import com.dianping.pigeon.remoting.invoker.client.ClientConfig;
import com.dianping.pigeon.remoting.invoker.client.HeartbeatTask;
import com.dianping.pigeon.remoting.invoker.process.ResponseProcessor;
import com.dianping.pigeon.remoting.invoker.route.region.Region;
import com.dianping.pigeon.remoting.invoker.route.region.RegionPolicyManager;
import com.dianping.pigeon.remoting.invoker.route.statistics.ServiceStatisticsHolder;
import com.dianping.pigeon.threadpool.NamedThreadFactory;
public abstract class AbstractClient implements Client {
protected final Logger logger = LoggerLoader.getLogger(getClass());
protected volatile Region region;
protected volatile boolean isActive = true;
protected final AtomicBoolean isClosed = new AtomicBoolean(true);
private final ResponseProcessor responseProcessor;
private ScheduledFuture<?> heatbeatTimer;
protected ClientConfig clientConfig;
private static final ScheduledThreadPoolExecutor scheduled = new ScheduledThreadPoolExecutor(
4, new NamedThreadFactory("Pigeon-Client-HeartBeat-ThreadPool", true));
public AbstractClient(ClientConfig clientConfig, ResponseProcessor responseProcessor) {
this.clientConfig = clientConfig;
this.responseProcessor = responseProcessor;
}
public void open() {
if (isClosed.compareAndSet(true, false)) {
doOpen();
startHeatbeat();
}
}
public abstract void doOpen();
public void close() {
if (isClosed.compareAndSet(false, true)) {
doClose();
stopHeartbeat();
}
}
public abstract void doClose();
@Override
public InvocationResponse write(InvocationRequest request) throws NetworkException {
ServiceStatisticsHolder.flowIn(request, this.getAddress());
try {
return doWrite(request);
} catch (NetworkException e) {
ServiceStatisticsHolder.flowOut(request, this.getAddress());
throw e;
}
}
public abstract InvocationResponse doWrite(InvocationRequest request) throws NetworkException;
@Override
public void processResponse(InvocationResponse response) {
this.responseProcessor.processResponse(response, this);
}
@Override
public boolean isClosed() {
return isClosed.get();
}
@Override
public boolean isActive() {
return isActive;
}
@Override
public void setActive(boolean active) {
this.isActive = active;
}
@Override
public Region getRegion() {
if (region == null) {
region = RegionPolicyManager.INSTANCE.getRegion(getHost());
}
return region;
}
@Override
public void clearRegion() {
region = null;
}
private void startHeatbeat() {
stopHeartbeat();
if (clientConfig.isHeartbeated() && Constants.PROTOCOL_DEFAULT.equals(getProtocol())) {
heatbeatTimer = scheduled.scheduleWithFixedDelay(
new HeartbeatTask(clientConfig, AbstractClient.this),
clientConfig.getHeartbeatInterval() * 4,
clientConfig.getHeartbeatInterval(),
TimeUnit.MILLISECONDS);
}
}
private void stopHeartbeat() {
if (heatbeatTimer != null && !heatbeatTimer.isCancelled()) {
try {
heatbeatTimer.cancel(true);
scheduled.purge();
} catch (Throwable e) {
logger.warn(e.getMessage(), e);
}
}
heatbeatTimer = null;
}
}