/* * (C) Copyright 2015-2016 the original author or authors. * * 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. * * Contributors: * ohun@live.cn (夜色) */ package com.mpush.common.message; import com.mpush.api.Message; import com.mpush.api.connection.Connection; import com.mpush.api.connection.SessionContext; import com.mpush.api.protocol.Packet; import com.mpush.api.spi.common.Json; import com.mpush.tools.Jsons; import com.mpush.tools.common.IOUtils; import com.mpush.tools.common.Profiler; import com.mpush.tools.config.CC; import io.netty.channel.ChannelFutureListener; import java.net.InetSocketAddress; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.atomic.AtomicInteger; /** * Created by ohun on 2015/12/28. * * @author ohun@live.cn */ public abstract class BaseMessage implements Message { private static final byte STATUS_DECODED = 1; private static final byte STATUS_ENCODED = 2; private static final AtomicInteger ID_SEQ = new AtomicInteger(); transient protected Packet packet; transient protected Connection connection; transient private byte status = 0; public BaseMessage(Packet packet, Connection connection) { this.packet = packet; this.connection = connection; } @Override public void decodeBody() { if ((status & STATUS_DECODED) == 0) { status |= STATUS_DECODED; if (packet.getBodyLength() > 0) { if (packet.hasFlag(Packet.FLAG_JSON_BODY)) { decodeJsonBody0(); } else { decodeBinaryBody0(); } } } } @Override public void encodeBody() { if ((status & STATUS_ENCODED) == 0) { status |= STATUS_ENCODED; if (packet.hasFlag(Packet.FLAG_JSON_BODY)) { encodeJsonBody0(); } else { encodeBinaryBody0(); } } } private void decodeBinaryBody0() { //1.解密 byte[] tmp = packet.body; if (packet.hasFlag(Packet.FLAG_CRYPTO)) { if (connection.getSessionContext().cipher != null) { tmp = connection.getSessionContext().cipher.decrypt(tmp); } } //2.解压 if (packet.hasFlag(Packet.FLAG_COMPRESS)) { tmp = IOUtils.decompress(tmp); } if (tmp.length == 0) { throw new RuntimeException("message decode ex"); } packet.body = tmp; Profiler.enter("time cost on [body decode]"); decode(packet.body); Profiler.release(); packet.body = null;// 释放内存 } private void encodeBinaryBody0() { Profiler.enter("time cost on [body encode]"); byte[] tmp = encode(); Profiler.release(); if (tmp != null && tmp.length > 0) { //1.压缩 if (tmp.length > CC.mp.core.compress_threshold) { byte[] result = IOUtils.compress(tmp); if (result.length > 0) { tmp = result; packet.addFlag(Packet.FLAG_COMPRESS); } } //2.加密 SessionContext context = connection.getSessionContext(); if (context.cipher != null) { byte[] result = context.cipher.encrypt(tmp); if (result.length > 0) { tmp = result; packet.addFlag(Packet.FLAG_CRYPTO); } } packet.body = tmp; } } private void decodeJsonBody0() { Map<String, Object> body = packet.getBody(); decodeJsonBody(body); } private void encodeJsonBody0() { packet.setBody(encodeJsonBody()); } private void encodeJsonStringBody0() { packet.setBody(encodeJsonStringBody()); } protected String encodeJsonStringBody() { return Jsons.toJson(this); } private void encodeBodyRaw() { if ((status & STATUS_ENCODED) == 0) { status |= STATUS_ENCODED; if (packet.hasFlag(Packet.FLAG_JSON_BODY)) { encodeJsonBody0(); } else { packet.body = encode(); } } } public abstract void decode(byte[] body); public abstract byte[] encode(); protected void decodeJsonBody(Map<String, Object> body) { } protected Map<String, Object> encodeJsonBody() { return null; } @Override public Packet getPacket() { return packet; } @Override public Connection getConnection() { return connection; } @Override public void send(ChannelFutureListener listener) { encodeBody(); connection.send(packet, listener); } @Override public void sendRaw(ChannelFutureListener listener) { encodeBodyRaw(); connection.send(packet, listener); } public void send() { send(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); } public void sendRaw() { sendRaw(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); } public void close() { send(ChannelFutureListener.CLOSE); } protected static int genSessionId() { return ID_SEQ.incrementAndGet(); } public int getSessionId() { return packet.sessionId; } public BaseMessage setRecipient(InetSocketAddress recipient) { packet.setRecipient(recipient); return this; } public void setPacket(Packet packet) { this.packet = packet; } public void setConnection(Connection connection) { this.connection = connection; } public ScheduledExecutorService getExecutor() { return connection.getChannel().eventLoop(); } public void runInRequestThread(Runnable runnable) { connection.getChannel().eventLoop().execute(runnable); } @Override public abstract String toString(); }