/*
* (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.server.network;
import java.util.concurrent.ThreadPoolExecutor;
import javax.transaction.xa.XAException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.taobao.gecko.service.Connection;
import com.taobao.gecko.service.RequestProcessor;
import com.taobao.metamorphosis.network.BooleanCommand;
import com.taobao.metamorphosis.network.HttpStatus;
import com.taobao.metamorphosis.network.RemotingUtils;
import com.taobao.metamorphosis.network.TransactionCommand;
import com.taobao.metamorphosis.server.CommandProcessor;
import com.taobao.metamorphosis.transaction.TransactionId;
/**
* �����������
*
* @author boyan(boyan@taobao.com)
* @date 2011-8-17
*
*/
public class TransactionProcessor implements RequestProcessor<TransactionCommand> {
private final CommandProcessor processor;
private final ThreadPoolExecutor executor;
public TransactionProcessor(final CommandProcessor processor, final ThreadPoolExecutor executor) {
super();
this.processor = processor;
this.executor = executor;
}
@Override
public void handleRequest(final TransactionCommand request, final Connection conn) {
final TransactionId xid = request.getTransactionInfo().getTransactionId();
final SessionContext context = SessionContextHolder.getOrCreateSessionContext(conn, xid);
if (log.isDebugEnabled()) {
log.debug(request);
}
try {
switch (request.getTransactionInfo().getType()) {
case BEGIN:
this.processor.beginTransaction(context, xid, request.getTransactionInfo().getTimeout());
this.responseOK(request, conn);
break;
case END:
// ignore;
break;
case PREPARE:
final int rt = this.processor.prepareTransaction(context, xid);
// prepare����践��
RemotingUtils.response(conn,
new BooleanCommand(HttpStatus.Success, String.valueOf(rt), request.getOpaque()));
break;
// �ύ��,forget��rollback��ʱ����ͬ�����ã������ҪӦ��
case COMMIT_ONE_PHASE:
this.processor.commitTransaction(context, xid, true);
this.responseOK(request, conn);
break;
case COMMIT_TWO_PHASE:
this.processor.commitTransaction(context, xid, false);
this.responseOK(request, conn);
break;
case FORGET:
this.processor.forgetTransaction(context, xid);
this.responseOK(request, conn);
break;
case ROLLBACK:
this.processor.rollbackTransaction(context, xid);
this.responseOK(request, conn);
break;
case RECOVER:
final TransactionId[] xids =
this.processor.getPreparedTransactions(context, request.getTransactionInfo()
.getUniqueQualifier());
final StringBuilder sb = new StringBuilder();
boolean wasFirst = true;
for (final TransactionId id : xids) {
if (wasFirst) {
sb.append(id.getTransactionKey());
wasFirst = false;
}
else {
sb.append("\r\n").append(id.getTransactionKey());
}
}
RemotingUtils
.response(conn, new BooleanCommand(HttpStatus.Success, sb.toString(), request.getOpaque()));
break;
default:
RemotingUtils.response(conn, new BooleanCommand(HttpStatus.InternalServerError, "Unknow transaction command type:" + request.getTransactionInfo().getType(),
request.getOpaque()));
}
}
catch (final XAException e) {
log.error("Processing transaction command failed", e);
// xa�쳣������ÿͻ��˿���ֱ���׳�
this.responseXAE(request, conn, e);
}
catch (final Exception e) {
log.error("Processing transaction command failed", e);
if (e.getCause() instanceof XAException) {
this.responseXAE(request, conn, (XAException) e.getCause());
}
else {
this.responseError(request, conn, e);
}
}
}
private void responseError(final TransactionCommand request, final Connection conn, final Exception e) {
RemotingUtils.response(conn,
new BooleanCommand(HttpStatus.InternalServerError, e.getMessage(), request.getOpaque()));
}
private void responseXAE(final TransactionCommand request, final Connection conn, final XAException e) {
RemotingUtils.response(conn, new BooleanCommand(HttpStatus.InternalServerError, "XAException:code=" + e.errorCode + ",msg=" + e.getMessage(),
request.getOpaque()));
}
static final Log log = LogFactory.getLog(TransactionProcessor.class);
private void responseOK(final TransactionCommand request, final Connection conn) {
RemotingUtils.response(conn, new BooleanCommand(HttpStatus.Success, null, request.getOpaque()));
}
@Override
public ThreadPoolExecutor getExecutor() {
return this.executor;
}
}