/*
* (C) 2007-2012 Alibaba Group Holding Limited.
*
* 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.
* Authors:
* wuhua <wq163@163.com> , boyan <killme2008@gmail.com>
*/
package com.taobao.metamorphosis.tools.monitor.msgprobe;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import com.taobao.metamorphosis.tools.monitor.InitException;
import com.taobao.metamorphosis.tools.monitor.core.AbstractProber;
import com.taobao.metamorphosis.tools.monitor.core.CoreManager;
import com.taobao.metamorphosis.tools.monitor.core.MsgReceiver;
import com.taobao.metamorphosis.tools.monitor.core.MsgSender;
import com.taobao.metamorphosis.tools.monitor.core.ProbTask;
import com.taobao.metamorphosis.tools.monitor.core.ReveiceResult;
import com.taobao.metamorphosis.tools.monitor.core.SendResultWrapper;
/**
* @author ��
* @since 2011-5-24 ����01:52:50
*/
public class MsgProber extends AbstractProber {
// private static Logger logger = Logger.getLogger(MsgProber.class);
private final List<ProbeListener> probeListeners = new ArrayList<ProbeListener>();
private InnerProbeListener innerProbeListener;
private volatile AtomicBoolean isInited = new AtomicBoolean(false);
public MsgProber(CoreManager coreManager) {
super(coreManager);
}
public void init() throws InitException {
if (this.isInited.compareAndSet(false, true)) {
try {
this.innerProbeListener = new InnerProbeListener();
this.logger.info("publish topics...");
this.publishTopics(this.getSenders());
this.addListener(new DefaultProbeListener());
this.addListener(new AlarmProbeListener(this.getMonitorConfig()));
}
catch (Exception e) {
throw new InitException("unexpected errer at init", e);
}
}
}
private final class ProbOneBrokerTask extends ProbTask {
MsgSender sender;
MsgReceiver receiver;
MsgProber prober;
ProbOneBrokerTask(MsgSender sender, MsgReceiver receiver, MsgProber prober) {
this.sender = sender;
this.receiver = receiver;
this.prober = prober;
}
@Override
protected void doExecute() throws Exception {
if (MsgProber.this.getLogger().isDebugEnabled()) {
MsgProber.this.getLogger().debug("msg prob...");
}
this.prober.prob(this.sender, this.receiver);
}
@Override
protected void handleException(Throwable e) {
MsgProber.this.logger.error(
"unexpected error in msg prob thread. broker server: " + this.sender.getServerUrl(), e);
}
}
private final List<ScheduledFuture<?>> futures = new ArrayList<ScheduledFuture<?>>();
@Override
public void doProb() throws InterruptedException {
// ��֤һ��sender��reveicerͬһʱ����ֻ����һ���߳���ʹ��
StringBuilder sb = new StringBuilder();
for (int i = 0; i < this.getSenders().length; i++) {
this.futures.add(this.getProberExecutor().scheduleWithFixedDelay(
new ProbOneBrokerTask(this.getSenders()[i], this.getReveicers()[i], this), 0,
this.getMonitorConfig().getMsgProbeCycleTime(), TimeUnit.MILLISECONDS));
sb.append("msg probe started:").append(this.getSenders()[i].getServerUrl()).append("\n");
}
this.logger.info(sb.toString());
}
@Override
protected void doStopProb() {
cancelFutures(this.futures);
}
public void addListener(ProbeListener listener) {
this.probeListeners.add(listener);
}
private void prob(MsgSender sender, MsgReceiver receiver) throws InterruptedException {
SendResultWrapper sendResult = sender.sendMessage(this.getMonitorConfig().getSendTimeout());
ProbContext probContext = new ProbContext();
probContext.lastSendTime = System.currentTimeMillis();
probContext.sendResult = sendResult;
if (!sendResult.isSuccess()) {
this.innerProbeListener.onSendFail(sender, sendResult);
return;
}
Thread.sleep(this.getMonitorConfig().getProbeInterval());
// receive����ֱ������,.
// ֱ������ʱ���ص�patitionΪbrokerId=-1,patition=��ʵ��patition
ReveiceResult reveiceResult = receiver.get(sender.getTopic(), sendResult.getSendResult().getPartition());
probContext.lastRevTime = System.currentTimeMillis();
probContext.reveiceResult = reveiceResult;
if (!reveiceResult.isSuccess()) {
this.innerProbeListener.onReceiveFail(probContext);
}
// ��һ�ν�����Ϣ��offset����һ�η��͵�offsetλ�ÿ�ʼ
receiver.setOffset(sendResult.getSendResult().getPartition(), sendResult.getSendResult().getOffset());
}
private void publishTopics(MsgSender[] senders) {
for (int i = 0; i < senders.length; i++) {
senders[i].publish();
}
}
final private class InnerProbeListener extends ProbeListener {
@Override
public void onSendFail(MsgSender sender, SendResultWrapper result) {
for (ProbeListener probeListener : MsgProber.this.probeListeners) {
try {
probeListener.onSendFail(sender, result);
}
catch (Exception e) {
MsgProber.this.logger.error("������ʧ���¼�ʱ��������," + probeListener.getClass(), e);
}
}
}
@Override
public void onReceiveFail(ProbContext probContext) {
for (ProbeListener probeListener : MsgProber.this.probeListeners) {
try {
probeListener.onReceiveFail(probContext);
}
catch (Exception e) {
MsgProber.this.logger.error("�������ʧ���¼�ʱ��������," + probeListener.getClass(), e);
}
}
}
}
static public class ProbContext {
SendResultWrapper sendResult;
ReveiceResult reveiceResult;
long lastSendTime;// ��һ�η�����Ϣ��ʱ��,����
long lastRevTime; // ���ν��յ���Ϣ��ʱ��,����
public long getSendRevInterval() {
return (this.lastRevTime - this.lastSendTime) / 1000;
}
public SendResultWrapper getSendResult() {
return this.sendResult;
}
public void setSendResult(SendResultWrapper sendResult) {
this.sendResult = sendResult;
}
public ReveiceResult getReveiceResult() {
return this.reveiceResult;
}
public void setReveiceResult(ReveiceResult reveiceResult) {
this.reveiceResult = reveiceResult;
}
public long getLastSendTime() {
return this.lastSendTime;
}
public void setLastSendTime(long lastSendTime) {
this.lastSendTime = lastSendTime;
}
public long getLastRevTime() {
return this.lastRevTime;
}
public void setLastRevTime(long lastRevTime) {
this.lastRevTime = lastRevTime;
}
}
}