package com.meidusa.amoeba.aladdin.handler;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import com.meidusa.amoeba.context.ProxyRuntimeContext;
import com.meidusa.amoeba.mysql.handler.PreparedStatmentInfo;
import com.meidusa.amoeba.mysql.net.MysqlClientConnection;
import com.meidusa.amoeba.mysql.net.packet.ErrorPacket;
import com.meidusa.amoeba.mysql.net.packet.ExecutePacket;
import com.meidusa.amoeba.mysql.net.packet.LongDataPacket;
import com.meidusa.amoeba.mysql.net.packet.MysqlPacketBuffer;
import com.meidusa.amoeba.mysql.net.packet.OkPacket;
import com.meidusa.amoeba.mysql.net.packet.QueryCommandPacket;
import com.meidusa.amoeba.net.Connection;
import com.meidusa.amoeba.net.MessageHandler;
import com.meidusa.amoeba.net.Sessionable;
import com.meidusa.amoeba.net.poolable.ObjectPool;
import com.meidusa.amoeba.route.QueryRouter;
import com.meidusa.amoeba.util.ByteUtil;
import com.meidusa.amoeba.util.StringFillFormat;
/**
* @author struct
* @author hexianmao
*/
public class AladdinMessageDispatcher implements MessageHandler {
private static Logger logger = Logger.getLogger(AladdinMessageDispatcher.class);
private static long timeout = -1;
private static byte[] STATIC_OK_BUFFER;
private static int fillLength = 18;
static {
OkPacket ok = new OkPacket();
ok.affectedRows = 0;
ok.insertId = 0;
ok.packetId = 1;
ok.serverStatus = 2;
STATIC_OK_BUFFER = ok.toByteBuffer(null).array();
}
public void handleMessage(Connection connection, byte[] message) {
MysqlClientConnection conn = (MysqlClientConnection) connection;
try {
if (MysqlPacketBuffer.isPacketType(message, QueryCommandPacket.COM_QUIT)) {
if (logger.isDebugEnabled()) {
logger.debug("COM_QUIT command");
}
return;
} else if (MysqlPacketBuffer.isPacketType(message, QueryCommandPacket.COM_STMT_CLOSE)) {
if (logger.isDebugEnabled()) {
logger.debug("COM_STMT_CLOSE command");
}
return;
} else if (MysqlPacketBuffer.isPacketType(message, QueryCommandPacket.COM_PING)) {
if (logger.isDebugEnabled()) {
logger.debug("COM_PING command");
}
conn.postMessage(STATIC_OK_BUFFER);
} else if (MysqlPacketBuffer.isPacketType(message, QueryCommandPacket.COM_QUERY)) {
QueryCommandPacket packet = new QueryCommandPacket();
packet.init(message, connection);
if (logger.isDebugEnabled()) {
logger.debug(StringFillFormat.format("COM_QUERY:", fillLength) + packet);
}
QueryRouter router = ProxyRuntimeContext.getInstance().getQueryRouter();
ObjectPool[] pools = router.doRoute(conn, packet.query, false, null);
if (pools == null) {
conn.postMessage(STATIC_OK_BUFFER);
return;
}
MessageHandler handler = new QueryCommandMessageHandler(conn, packet.query, null, pools, timeout);
if (handler instanceof Sessionable) {
Sessionable session = (Sessionable) handler;
try {
session.startSession();
} catch (Exception e) {
logger.error("start Session error:", e);
throw e;
} finally {
session.endSession();
}
}
} else if (MysqlPacketBuffer.isPacketType(message, QueryCommandPacket.COM_STMT_PREPARE)) {
QueryCommandPacket packet = new QueryCommandPacket();
packet.init(message, connection);
if (logger.isDebugEnabled()) {
logger.debug(StringFillFormat.format("COM_STMT_PREPARE:", fillLength) + packet);
}
PreparedStatmentInfo pInfo = conn.getPreparedStatmentInfo(packet.query);
byte[] buffer = pInfo.getByteBuffer();
conn.postMessage(buffer);
return;
} else if (MysqlPacketBuffer.isPacketType(message, QueryCommandPacket.COM_STMT_SEND_LONG_DATA)) {
if (logger.isDebugEnabled()) {
logger.debug("COM_STMT_SEND_LONG_DATA");
}
conn.addLongData(message);
} else if (MysqlPacketBuffer.isPacketType(message, QueryCommandPacket.COM_STMT_EXECUTE)) {
long statmentId = ExecutePacket.readStatmentID(message);
PreparedStatmentInfo pInfo = conn.getPreparedStatmentInfo(statmentId);
if (pInfo == null) {
logger.error("Unknown prepared statment id:" + statmentId);
ErrorPacket error = new ErrorPacket();
error.errno = 1044;
error.packetId = 1;
error.sqlstate = "42000";
error.serverErrorMessage = "Unknown prepared statment id=" + statmentId;
conn.postMessage(error.toByteBuffer(connection).array());
} else {
String sql = pInfo.getPreparedStatment();
if (logger.isDebugEnabled()) {
logger.debug(StringFillFormat.format("COM_STMT_EXECUTE:", fillLength) + "sql[" + sql.trim() + "]");
logger.debug(StringFillFormat.format("COM_STMT_EXECUTE:", fillLength) + "params[" + pInfo.getParameterCount() + "]");
logger.debug(StringFillFormat.format("COM_STMT_EXECUTE:", fillLength) + "dump bytes[" + ByteUtil.toHex(message, 0, message.length) + "]");
}
Map<Integer, Object> longMap = null;
if (conn.getLongDataList().size() > 0) {
longMap = new HashMap<Integer, Object>();
for (byte[] longdate : conn.getLongDataList()) {
LongDataPacket packet = new LongDataPacket();
packet.init(longdate, connection);
longMap.put(packet.parameterIndex, packet.data);
}
conn.clearLongData();
}
ExecutePacket packet = new ExecutePacket(pInfo, longMap);
packet.init(message, connection);
if (logger.isDebugEnabled()) {
logger.debug(StringFillFormat.format("COM_STMT_EXECUTE:", fillLength) + "[" + packet + "]");
}
QueryRouter router = ProxyRuntimeContext.getInstance().getQueryRouter();
ObjectPool[] pools = router.doRoute(conn, sql, false, packet.getParameters());
PreparedStatmentExecuteMessageHandler handler = new PreparedStatmentExecuteMessageHandler(conn, pInfo, packet, pools, timeout);
if (handler instanceof Sessionable) {
Sessionable session = (Sessionable) handler;
try {
session.startSession();
} catch (Exception e) {
logger.error("start Session error:", e);
throw e;
} finally {
session.endSession();
}
}
}
} else if (MysqlPacketBuffer.isPacketType(message, QueryCommandPacket.COM_INIT_DB)) {
QueryCommandPacket packet = new QueryCommandPacket();
packet.init(message, connection);
if (logger.isDebugEnabled()) {
logger.debug(StringFillFormat.format("COM_INIT_DB:", fillLength) + packet);
}
conn.setSchema(packet.query);
conn.postMessage(STATIC_OK_BUFFER);
} else {
QueryCommandPacket packet = new QueryCommandPacket();
packet.init(message, connection);
logger.error("Aladdin unsupport packet:" + packet);
ErrorPacket error = new ErrorPacket();
error.errno = 1044;
error.packetId = 1;
error.sqlstate = "42000";
error.serverErrorMessage = "can not use this command here!!";
conn.postMessage(error.toByteBuffer(connection).array());
}
} catch (Exception e) {
logger.error("Aladdin dispatch message error", e);
ErrorPacket error = new ErrorPacket();
error.errno = 1044;
error.packetId = 1;
error.sqlstate = "42000";
error.serverErrorMessage = e.getMessage();
conn.postMessage(error.toByteBuffer(connection).array());
}
}
}