/**
* Dianping.com Inc.
* Copyright (c) 2003-2013 All Rights Reserved.
*/
package com.dianping.pigeon.remoting.invoker.concurrent;
import java.io.Serializable;
import java.util.Map;
import com.dianping.pigeon.log.Logger;
import com.dianping.pigeon.log.LoggerLoader;
import com.dianping.pigeon.monitor.Monitor;
import com.dianping.pigeon.monitor.MonitorLoader;
import com.dianping.pigeon.monitor.MonitorTransaction;
import com.dianping.pigeon.remoting.common.monitor.trace.InvokerMonitorData;
import com.dianping.pigeon.remoting.common.domain.InvocationContext.TimePhase;
import com.dianping.pigeon.remoting.common.domain.InvocationContext.TimePoint;
import com.dianping.pigeon.remoting.common.domain.InvocationRequest;
import com.dianping.pigeon.remoting.common.domain.InvocationResponse;
import com.dianping.pigeon.remoting.common.domain.generic.UnifiedResponse;
import com.dianping.pigeon.remoting.common.exception.BadResponseException;
import com.dianping.pigeon.remoting.common.exception.RpcException;
import com.dianping.pigeon.remoting.common.monitor.SizeMonitor;
import com.dianping.pigeon.remoting.common.util.Constants;
import com.dianping.pigeon.remoting.common.util.ContextUtils;
import com.dianping.pigeon.remoting.common.util.InvocationUtils;
import com.dianping.pigeon.remoting.invoker.Client;
import com.dianping.pigeon.remoting.invoker.config.InvokerConfig;
import com.dianping.pigeon.remoting.invoker.domain.InvokerContext;
import com.dianping.pigeon.remoting.invoker.process.DegradationManager;
import com.dianping.pigeon.remoting.invoker.process.ExceptionManager;
import com.dianping.pigeon.remoting.invoker.process.filter.DegradationFilter;
public class ServiceCallbackWrapper implements Callback {
private static final Logger logger = LoggerLoader.getLogger(ServiceCallbackWrapper.class);
private static final Monitor monitor = MonitorLoader.getMonitor();
private InvocationResponse response;
private InvocationRequest request;
private Client client;
private InvocationCallback callback;
private InvokerContext invocationContext;
public ServiceCallbackWrapper(InvokerContext invocationContext, InvocationCallback callback) {
this.invocationContext = invocationContext;
this.callback = callback;
}
@Override
public void run() {
InvokerConfig<?> invokerConfig = invocationContext.getInvokerConfig();
MonitorTransaction transaction = null;
long currentTime = System.currentTimeMillis();
String addr = null;
if (client != null) {
addr = client.getAddress();
}
boolean isSuccess = false;
String callInterface = InvocationUtils.getRemoteCallFullName(invokerConfig.getUrl(),
invocationContext.getMethodName(), invocationContext.getParameterTypes());
try {
setResponseContext(response);
if (Constants.MONITOR_ENABLE) {
transaction = monitor.createTransaction("PigeonCallback", callInterface, invocationContext);
}
if (transaction != null) {
transaction.setStatusOk();
transaction.logEvent("PigeonCall.callType", invokerConfig.getCallType(), "");
transaction.logEvent("PigeonCall.serialize", request.getSerialize() + "", "");
transaction.logEvent("PigeonCall.timeout", invokerConfig.getTimeout() + "", "");
if (response != null && response.getSize() > 0) {
String respSize = SizeMonitor.getInstance().getLogSize(response.getSize());
if (respSize != null) {
monitor.logEvent("PigeonCall.responseSize", respSize, "" + response.getSize());
}
invocationContext.getTimeline().add(new TimePoint(TimePhase.R, response.getCreateMillisTime()));
invocationContext.getTimeline().add(new TimePoint(TimePhase.R, currentTime));
}
}
if (request.getTimeout() > 0 && request.getCreateMillisTime() > 0
&& request.getCreateMillisTime() + request.getTimeout() < currentTime) {
StringBuilder msg = new StringBuilder();
msg.append("request callback timeout:").append(request);
Exception e = InvocationUtils.newTimeoutException(msg.toString());
e.setStackTrace(new StackTraceElement[]{});
InvocationResponse degradedResponse = null;
if (DegradationManager.INSTANCE.needFailureDegrade(invocationContext)) {
try {
invocationContext.getDegradeInfo().setFailureDegrade(true);
invocationContext.getDegradeInfo().setCause(e);
degradedResponse = DegradationFilter.degradeCall(invocationContext, false);
} catch (Throwable t) {
logger.warn("failure degrade in callback call type error: " + t.toString());
}
}
if (degradedResponse == null) {
DegradationManager.INSTANCE.addFailedRequest(invocationContext, e);
ExceptionManager.INSTANCE.logRpcException(addr, invocationContext.getInvokerConfig().getUrl(),
invocationContext.getMethodName(), "request callback timeout", e, request, response,
transaction);
}
}
} finally {
try {
if (response.getMessageType() == Constants.MESSAGE_TYPE_SERVICE) {
completeTransaction(transaction);
isSuccess = true;
this.callback.onSuccess(response.getReturn());
} else if (response.getMessageType() == Constants.MESSAGE_TYPE_EXCEPTION) {
RpcException e = ExceptionManager.INSTANCE.logRemoteCallException(addr,
invocationContext.getInvokerConfig().getUrl(), invocationContext.getMethodName(),
"remote call error with callback", request, response, transaction);
InvocationResponse degradedResponse = null;
if (DegradationManager.INSTANCE.needFailureDegrade(invocationContext)) {
try {
invocationContext.getDegradeInfo().setFailureDegrade(true);
invocationContext.getDegradeInfo().setCause(e);
degradedResponse = DegradationFilter.degradeCall(invocationContext, false);
} catch (Throwable t) {
logger.warn("failure degrade in callback call type error: " + t.toString());
}
}
if (degradedResponse == null) {
DegradationManager.INSTANCE.addFailedRequest(invocationContext, e);
}
completeTransaction(transaction);
if (degradedResponse == null) {
this.callback.onFailure(e);
}
} else if (response.getMessageType() == Constants.MESSAGE_TYPE_SERVICE_EXCEPTION) {
Exception e = ExceptionManager.INSTANCE
.logRemoteServiceException("remote service biz error with callback", request, response);
completeTransaction(transaction);
this.callback.onFailure(e);
} else {
RpcException e = new BadResponseException(response.toString());
monitor.logError(e);
completeTransaction(transaction);
}
} catch (Throwable e) {
logger.error("error while executing service callback", e);
} finally {
if (transaction != null) {
DegradationManager.INSTANCE.monitorDegrade(invocationContext, transaction);
}
}
InvokerMonitorData monitorData = (InvokerMonitorData) invocationContext.getMonitorData();
if (monitorData != null) {
monitorData.setIsSuccess(isSuccess);
monitorData.complete();
}
}
}
private void completeTransaction(MonitorTransaction transaction) {
if (transaction != null) {
invocationContext.getTimeline().add(new TimePoint(TimePhase.E, System.currentTimeMillis()));
try {
transaction.complete();
} catch (Throwable e) {
monitor.logMonitorError(e);
}
}
}
protected void setResponseContext(InvocationResponse response) {
if (response == null) {
return;
}
if (response instanceof UnifiedResponse) {
UnifiedResponse _response = (UnifiedResponse) response;
Map<String, String> responseValues = _response.getLocalContext();
if (responseValues != null) {
ContextUtils.setResponseContext((Map) responseValues);
}
} else {
Map<String, Serializable> responseValues = response.getResponseValues();
if (responseValues != null) {
ContextUtils.setResponseContext(responseValues);
}
}
}
@Override
public void setClient(Client client) {
this.client = client;
}
@Override
public Client getClient() {
return this.client;
}
@Override
public void callback(InvocationResponse response) {
this.response = response;
}
@Override
public void setRequest(InvocationRequest request) {
this.request = request;
}
@Override
public void dispose() {
}
}