/* * (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. */ package com.taobao.gecko.service.callback; import java.net.InetSocketAddress; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import com.taobao.gecko.core.command.RequestCommand; import com.taobao.gecko.core.command.ResponseCommand; import com.taobao.gecko.core.command.ResponseStatus; import com.taobao.gecko.core.command.kernel.BooleanAckCommand; import com.taobao.gecko.core.nio.impl.TimerRef; import com.taobao.gecko.service.Connection; import com.taobao.gecko.service.impl.DefaultConnection; import com.taobao.gecko.service.impl.RequestCallBack; /** * * �ص����� * * @author boyan * * @since 1.0, 2009-12-18 ����04:09:25 */ public abstract class AbstractRequestCallBack implements RequestCallBack { private final long timeout; // ��ʱʱ�䣬��λ���� private final long timestamp; // ������ʱ��� private TimerRef timerRef; // ��ʱ������ private final CountDownLatch countDownLatch; // ������� private final ConcurrentHashMap<Connection, Future<Boolean>> writeFutureMap = new ConcurrentHashMap<Connection, Future<Boolean>>(); // ��ֹ�ظ���Ӧ���� protected final Lock responseLock = new ReentrantLock(); public AbstractRequestCallBack(final CountDownLatch countDownLatch, final long timeout, final long timestamp) { super(); this.countDownLatch = countDownLatch; this.timeout = timeout; this.timestamp = timestamp; } public void cancelWrite(final Connection conn) { if (conn == null) { return; } final Future<Boolean> future = this.writeFutureMap.remove(conn); if (future != null) { future.cancel(false); } } public void addWriteFuture(final Connection conn, final Future<Boolean> future) { this.writeFutureMap.put(conn, future); } public void countDownLatch() { this.responseLock.lock(); try { this.countDownLatch.countDown(); } finally { this.responseLock.unlock(); } } public boolean await(final long timeout, final TimeUnit unit) throws InterruptedException { return this.countDownLatch.await(timeout, unit); } /** * ȡ����ʱ�� */ public void cancelTimer() { if (this.timerRef != null) { this.timerRef.cancel(); } } public void setTimerRef(final TimerRef timerRef) { this.timerRef = timerRef; } public boolean isInvalid(final long now) { return this.timeout <= 0 || now - this.timestamp > this.timeout; } protected static final BooleanAckCommand createComunicationErrorResponseCommand(final Connection conn, final Exception e, final RequestCommand requestCommand, final InetSocketAddress address) { final StringBuilder sb = new StringBuilder(e.getMessage()); if (e.getCause() != null) { sb.append("\r\nRroot cause by:\r\n").append(e.getCause().getMessage()); } final BooleanAckCommand value = conn.getRemotingContext() .getCommandFactory() .createBooleanAckCommand(requestCommand.getRequestHeader(), ResponseStatus.ERROR_COMM, sb.toString()); value.setResponseStatus(ResponseStatus.ERROR_COMM); value.setResponseTime(System.currentTimeMillis()); value.setResponseHost(address); return value; } public void onResponse(final String group, final ResponseCommand responseCommand, final Connection connection) { if (responseCommand != null) { this.removeCallBackFromConnection(connection, responseCommand.getOpaque()); } this.onResponse0(group, responseCommand, connection); } public abstract void onResponse0(String group, ResponseCommand responseCommand, Connection connection); public abstract void setException0(Exception e, Connection conn, RequestCommand requestCommand); public void setException(final Exception e, final Connection conn, final RequestCommand requestCommand) { if (requestCommand != null) { this.removeCallBackFromConnection(conn, requestCommand.getOpaque()); } this.setException0(e, conn, requestCommand); } protected void removeCallBackFromConnection(final Connection conn, final Integer opaque) { if (conn != null) { ((DefaultConnection) conn).removeRequestCallBack(opaque); } } /** * �����Ƿ���� * * @return */ public abstract boolean isComplete(); /** * ���������� */ public abstract void complete(); /** * ����������� * * @return */ public boolean tryComplete() { this.responseLock.lock(); try { // �Ѿ���� if (this.isComplete()) { return false; } // �������㣬������� if (this.countDownLatch.getCount() == 0) { // ������ this.complete(); // ȡ����ʱ�� this.cancelTimer(); return true; } return false; } finally { this.responseLock.unlock(); } } public void dispose() { this.writeFutureMap.clear(); if (this.timerRef != null) { this.timerRef.cancel(); } } public long getTimestamp() { return this.timestamp; } }