/** * <pre> * This program is free software; you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program; * if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * </pre> */ package com.meidusa.amoeba.mysql.net; import java.nio.channels.SocketChannel; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.collections.map.LRUMap; import org.apache.log4j.Logger; import com.meidusa.amoeba.context.ProxyRuntimeContext; import com.meidusa.amoeba.mysql.filter.IOFilter; import com.meidusa.amoeba.mysql.filter.PacketFilterInvocation; import com.meidusa.amoeba.mysql.filter.PacketIOFilter; import com.meidusa.amoeba.mysql.handler.PreparedStatmentInfo; import com.meidusa.amoeba.net.AuthingableConnectionManager; import com.meidusa.amoeba.net.Connection; import com.meidusa.amoeba.util.ThreadLocalMap; /** * �������ӵ� proxy server�Ŀͻ������Ӷ����װ * * @author <a href=mailto:piratebase@sina.com>Struct chen</a> */ public class MysqlClientConnection extends MysqlConnection { private static Logger logger = Logger .getLogger(MysqlClientConnection.class); static List<IOFilter> filterList = new ArrayList<IOFilter>(); static { filterList.add(new PacketIOFilter()); } // �������˷��͵�������ڿͻ��˼��ܵ��ַ��� protected String seed; // ����ͻ��˷��صļ��ܹ����ַ��� protected byte[] authenticationMessage; private List<byte[]> longDataList = new ArrayList<byte[]>(); private List<byte[]> unmodifiableLongDataList = Collections .unmodifiableList(new ArrayList<byte[]>()); /** �洢sql,statmentId�� */ private final Map<String, Long> SQL_STATMENT_ID_MAP = Collections .synchronizedMap(new HashMap<String, Long>(256)); private AtomicLong atomicLong = new AtomicLong(1); /** * ����LRU������ЩpreparedStatment��Ϣ key=statmentId value=PreparedStatmentInfo * object */ @SuppressWarnings("unchecked") private final Map<Long, PreparedStatmentInfo> PREPARED_STATMENT_MAP = Collections .synchronizedMap(new LRUMap(256) { private static final long serialVersionUID = 1L; protected boolean removeLRU(LinkEntry entry) { PreparedStatmentInfo info = (PreparedStatmentInfo) entry .getValue(); SQL_STATMENT_ID_MAP.remove(info.getPreparedStatment()); return true; } public PreparedStatmentInfo remove(Object key) { PreparedStatmentInfo info = (PreparedStatmentInfo) super .remove(key); SQL_STATMENT_ID_MAP.remove(info.getPreparedStatment()); return info; } public Object put(Object key, Object value) { PreparedStatmentInfo info = (PreparedStatmentInfo) value; SQL_STATMENT_ID_MAP.put(info.getPreparedStatment(), (Long) key); return super.put(key, value); } public void putAll(Map map) { for (Iterator it = map.entrySet().iterator(); it.hasNext();) { Map.Entry<Long, PreparedStatmentInfo> entry = (Map.Entry<Long, PreparedStatmentInfo>) it .next(); SQL_STATMENT_ID_MAP.put(entry.getValue() .getPreparedStatment(), entry.getKey()); } super.putAll(map); } }); public MysqlClientConnection(SocketChannel channel, long createStamp) { super(channel, createStamp); } public PreparedStatmentInfo getPreparedStatmentInfo(long id) { return PREPARED_STATMENT_MAP.get(id); } public PreparedStatmentInfo getPreparedStatmentInfo(String preparedSql) { Long id = SQL_STATMENT_ID_MAP.get(preparedSql); PreparedStatmentInfo info = null; if (id == null) { info = new PreparedStatmentInfo(this, atomicLong.getAndIncrement(), preparedSql); PREPARED_STATMENT_MAP.put(info.getStatmentId(), info); } else { info = getPreparedStatmentInfo(id); } return info; } public String getSeed() { return seed; } public void setSeed(String seed) { this.seed = seed; } public byte[] getAuthenticationMessage() { return authenticationMessage; } public void handleMessage(Connection conn, byte[] message) { // ��δ��֤ͨ����ʱ�� /** ��ʱ���յ���Ӧ������֤���ݣ���������Ϊ��֤�ṩ���� */ this.authenticationMessage = message; ((AuthingableConnectionManager) _cmgr).getAuthenticator() .authenticateConnection(this); } protected void messageProcess(final byte[] msg) { final PacketFilterInvocation invocation = new PacketFilterInvocation( filterList, this, msg) { @Override protected Result doProcess() { ProxyRuntimeContext.getInstance().getClientSideExecutor() .execute(new Runnable() { public void run() { try { MysqlClientConnection.this .getMessageHandler().handleMessage( MysqlClientConnection.this, msg); } finally { ThreadLocalMap.reset(); } } }); return null; } }; invocation.invoke(); } public void addLongData(byte[] longData) { longDataList.add(longData); } public void clearLongData() { longDataList.clear(); } public List<byte[]> getLongDataList() { return unmodifiableLongDataList; } /** * ���ڴ�����֤��Connection Idleʱ�����������Ӧ����һ�㡣 */ public boolean checkIdle(long now) { if (isAuthenticated()) { return false; } else { long idleMillis = now - _lastEvent; if (idleMillis < 5000) { return false; } if (isClosed()) { return true; } logger.warn("Disconnecting non-communicative client [conn=" + this + ", idle=" + idleMillis + "ms]."); return true; } } }