/**
* <pre>
* copy right meidusa.com
*
* This program is free software; you can redistribute it and/or modify it under the terms of
* the GNU AFFERO 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 AFFERO GENERAL PUBLIC LICENSE for more details.
* You should have received a copy of the GNU AFFERO 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.net.packet;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.nio.ByteBuffer;
import org.apache.commons.lang.builder.ToStringBuilder;
import com.meidusa.amoeba.net.Connection;
/**
* @author struct
*/
public abstract class AbstractPacket<T extends AbstractPacketBuffer> implements Packet {
public void init(byte[] buffer, Connection conn) {
T packetBuffer = constractorBuffer(buffer);
packetBuffer.init(conn);
init(packetBuffer);
afterRead(packetBuffer);
}
/**
* 分析数据包(分析包头+数据区域,分析完包头以后应该将Buffer的postion设置到数据区)
*/
protected void init(T buffer){
readHead(buffer);
readBody(buffer);
}
protected void readHead(T buffer){
}
protected void readBody(T buffer){
}
/**
* 做完初始化以后
*/
protected void afterRead(T buffer) {
}
public ByteBuffer toByteBuffer(Connection conn) {
try {
int bufferSize = calculatePacketSize();
T packetBuffer = constractorBuffer(bufferSize);
packetBuffer.init(conn);
return toBuffer(packetBuffer).toByteBuffer();
} catch (UnsupportedEncodingException e) {
return null;
}
}
private T constractorBuffer(int bufferSize) {
T buffer = null;
try {
Constructor<T> constractor = getPacketBufferClass().getConstructor(int.class);
buffer = constractor.newInstance(bufferSize);
} catch (Exception e) {
e.printStackTrace();
}
return buffer;
}
/**
* <pre>
* 该方法调用了{@link #write2Buffer(PacketBuffer)} 写入到指定的buffer,
* 并且调用了{@link #afterPacketWritten(PacketBuffer)}
* </pre>
*/
private T toBuffer(T buffer) throws UnsupportedEncodingException {
write2Buffer(buffer);
afterPacketWritten(buffer);
return buffer;
}
/**
* 包含头的消息封装
*/
protected void write2Buffer(T buffer) throws UnsupportedEncodingException{
writeHead(buffer);
writeBody(buffer);
}
protected void writeBody(T buffer) throws UnsupportedEncodingException {
}
protected void writeHead(T buffer){
}
/**
* <pre>
* 写完之后一定需要调用这个方法,buffer的指针位置指向末尾的下一个位置(包总长度位置)。
* 这儿一般是计算数据包总长度,或者其他需要数据包写完才能完成的数据
* </pre>
*/
protected abstract void afterPacketWritten(T buffer);
/**
* 估算packet的大小,估算的太大浪费内存,估算的太小会影响性能
*/
protected abstract int calculatePacketSize();
private T constractorBuffer(byte[] buffer) {
T packetbuffer = null;
try {
Constructor<T> constractor = getPacketBufferClass().getConstructor(byte[].class);
packetbuffer = constractor.newInstance(buffer);
} catch (Exception e) {
e.printStackTrace();
}
return packetbuffer;
}
protected abstract Class<T> getPacketBufferClass();
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
}