All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zbus.remoting.Message Maven / Gradle / Ivy

The newest version!
package org.zbus.remoting;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
 


public class Message implements Serializable { 
	private static final long serialVersionUID = 4379223525215626137L;

	public static final String HEARTBEAT         = "heartbeat"; //心跳消息
	
	//标准HTTP头部内容
	public static final String HEADER_CLIENT     = "remote-addr";
	public static final String HEADER_ENCODING   = "content-encoding";
	
	//常见扩展HTTP协议头部
	public static final String HEADER_BROKER     = "broker";
	public static final String HEADER_TOPIC      = "topic"; //使用,分隔 
	public static final String HEADER_MQ_REPLY   = "mq-reply";
	public static final String HEADER_MQ         = "mq";
	public static final String HEADER_TOKEN      = "token";
	public static final String HEADER_MSGID      = "msgid";	
	public static final String HEADER_MSGID_RAW  = "msgid-raw";
	public static final String HEADER_ACK        = "ack";	
	public static final String HEADER_REPLY_CODE = "reply-code";	
	
	 
	protected Meta meta = new Meta();
	protected Map head = new ConcurrentHashMap();
	protected byte[] body; 
	
	
	
	public Message(){
		setBody((byte[])null);
	} 
	
	public static Message copyWithoutBody(Message msg){
		Message res = new Message();
		res.meta = new Meta(msg.meta);
		res.head = new HashMap(msg.head);
		res.body = msg.body;
		return res;
	}
	
	public String getMetaString() {
		return meta.toString();
	}
	
	public Meta getMeta(){
		return meta;
	}
	
	public void setMeta(String meta) { 
		this.meta = new Meta(meta);
	}
	
	public void setMeta(Meta meta) { 
		this.meta = meta;
	}
	
	public Map getHead() {
		return head;
	} 
	
	public void setHead(Map head) {
		this.head = head;
	} 
	
	public String getHead(String key){
		return this.head.get(key);
	}
	
	public void setHead(String key, String value){
		if(value == null) return;
		this.head.put(key, value);
	} 
	
	public String removeHead(String key){
		return this.head.remove(key);
	}
	
	public String getParam(String key){
		return meta.getParam(key); 
	}
	
	public String getHeadOrParam(String key){ 
		String value = getHead(key);
		if(value == null){
			value = getParam(key); 
		} 
		return value;
	}
	
	public String getHeadOrParam(String key, String defaultValue) { 
		String value = getHeadOrParam(key);
		if(value == null){
			value = defaultValue;
		}
		return value;
	}   
	
	public byte[] getBody() {
		return body;
	}
	
	public void setBody(byte[] body) {
		int len = 0;
		if( body != null){
			len = body.length;
		}
		this.setHead("content-length", ""+len);
		this.body = body;
	}
	
	public void setBody(String body){
		setBody(body.getBytes());
	} 
	
	public Message setBody(String format, Object ...args) { 
		this.setBody(String.format(format, args));
		return this;
	} 
	
	public void setJsonBody(String body){
		this.setJsonBody(body.getBytes());
	}
	
	public void setJsonBody(byte[] body){
		this.setHead("content-type", "application/json");
		this.setBody(body);
	}
	
	public String getBodyString() {
		if (this.body == null) return null;
		return new String(this.body);
	}

	public String getBodyString(String encoding) {
		if (this.body == null) return null;
		try {
			return new String(this.body, encoding);
		} catch (UnsupportedEncodingException e) {
			return new String(this.body);
		}
	}
	
	//////////////////////////////////////////////////////////////
	
	public void decodeHeaders(byte[] data, int offset, int size){
		try{
			BufferedReader in = new BufferedReader(new InputStreamReader(new 
				ByteArrayInputStream(data, offset, size)));
	
			String meta = in.readLine();
			if(meta == null) return;
			this.meta = new Meta(meta);
			
			String line = in.readLine();
	        while (line != null && line.trim().length() > 0) {
	            int p = line.indexOf(':');
	            if (p >= 0){ 
	                head.put(line.substring(0, p).trim().toLowerCase(), line.substring(p + 1).trim());
	            } 
	            line = in.readLine();
	        }
		} catch(IOException e){
			e.printStackTrace();
		}
	}
	
	public int estimatedSize(){
		int size = 0;
		size += meta.toString().length();
		
		Iterator> iter = head.entrySet().iterator();
		while(iter.hasNext()){
			Entry e = iter.next();
			size += e.getKey().length() + e.getKey().length();
		} 
		
		if(body != null){
			size += body.length;
		}
		return size;
	} 
	
	public String getMqReply() {
		return this.getHeadOrParam(HEADER_MQ_REPLY);
	}
	public Message setMqReply(String value) {
		this.setHead(HEADER_MQ_REPLY, value);
		return this;
	}
	
	public String getEncoding() {
		return this.getHeadOrParam(HEADER_ENCODING);
	}
	public Message setEncoding(String encoding) {
		this.setHead(HEADER_ENCODING, encoding);
		return this;
	}
	
	
	public String getMsgId() {
		return this.getHeadOrParam(HEADER_MSGID);
	}
	public Message setMsgId(String msgId) {
		if(msgId == null) return this;
		this.setHead(HEADER_MSGID, msgId);
		return this;
	}
	
	
	public String getMsgIdRaw() {
		return this.getHeadOrParam(HEADER_MSGID_RAW);
	}
	public Message setMsgIdRaw(String value) {
		if(value == null) return this;
		this.setHead(HEADER_MSGID_RAW, value);
		return this;
	}
	
	public boolean isAck() {
		String ack = this.getHeadOrParam(HEADER_ACK);
		if(ack == null) return true; //默认ack为true
		ack = ack.trim().toLowerCase();
		return ack.equals("1");
	}
	
	public void setAck(boolean ack){
		String value = ack? "1":"0";
		this.setHead(HEADER_ACK, value);
	}
	
	public String getMq(){
		return this.getHeadOrParam(HEADER_MQ);
	}
	 
	public Message setMq(String mq) {
		this.setHead(HEADER_MQ, mq);
		return this;
	} 
	
	public String getToken() {
		return this.getHeadOrParam(HEADER_TOKEN);
	}
	public Message setToken(String token) {
		this.setHead(HEADER_TOKEN, token);
		return this;
	} 
	
	public String getTopic() {
		return getHeadOrParam(HEADER_TOPIC);
	}

	public Message setTopic(String topic) {
		this.setHead(HEADER_TOPIC, topic);
		return this;
	}  

	//////////特殊处理:Command 与 Status 兼容HTTP////////////// 
	public String getCommand() { //特殊处理 
		return meta.command; 
	} 
	public Message setCommand(String command) {
		meta.command = command;
		meta.status = null; //互斥
		return this;
	}   
	public String getStatus() {  
		return meta.status;
	}
	public Message setStatus(String status) { 
		meta.status = status;
		meta.command = null; //互斥
		return this; 
	}
	
	public boolean isStatus200() {
		return "200".equals(this.getStatus());
	}

	public boolean isStatus404() {
		return "404".equals(this.getStatus());
	}

	public boolean isStatus500() {
		return "500".equals(this.getStatus());
	}  
	
	protected String getBodyPrintString() {
		if (this.body == null)
			return null;
		if (this.body.length > 1024) {
			return new String(this.body, 0, 1024) + "...";
		} else {
			return getBodyString();
		}
	}
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append(meta+"\r\n");
		//优先Print msgId与MQ
		String msgid = head.get(HEADER_MSGID);
		String mq = head.get(HEADER_MQ);
		if(msgid != null){
			sb.append(HEADER_MSGID+": "+msgid+"\r\n");
		}
		if(mq != null){
			sb.append(HEADER_MQ+": "+mq+"\r\n");
		}
		
		for(Map.Entry e : head.entrySet()){
			if(e.getKey().equals(HEADER_MSGID)) continue;
			if(e.getKey().equals(HEADER_MQ)) continue;
			sb.append(e.getKey()+": "+e.getValue()+"\r\n");
		}
		sb.append("\r\n");
		sb.append(getBodyPrintString());
		return sb.toString();
	} 
	 
}



class Meta implements Serializable{ 
	private static final long serialVersionUID = -8557063231118504061L;
	//HTTP请求头部: 方法(GET/POST)-命令-参数
	String method = "GET"; 
	String command; 
	Map params;
	
	//HTTP响应头部: 状态(200)
	String status;
	
	static Set httpMethod = new HashSet();
	static Map httpStatus = new HashMap();
	
	static{ 
		httpMethod.add("GET");
		httpMethod.add("POST"); 
		httpMethod.add("PUT");
		httpMethod.add("DELETE");
		httpMethod.add("HEAD");
		httpMethod.add("OPTIONS"); 
		
		httpStatus.put("101", "Switching Protocols"); 
		httpStatus.put("200", "OK");
		httpStatus.put("201", "Created");
		httpStatus.put("202", "Accepted");
		httpStatus.put("204", "No Content"); 
		httpStatus.put("206", "Partial Content"); 
		httpStatus.put("301", "Moved Permanently");
		httpStatus.put("304", "Not Modified"); 
		httpStatus.put("400", "Bad Request"); 
		httpStatus.put("401", "Unauthorized"); 
		httpStatus.put("403", "Forbidden");
		httpStatus.put("404", "Not Found"); 
		httpStatus.put("405", "Method Not Allowed"); 
		httpStatus.put("416", "Requested Range Not Satisfiable");
		httpStatus.put("500", "Internal Server Error");
	}
	
	@Override
	public String toString() { 
		if(this.status != null){ //status存在,则认为是响应元数据
			String desc = httpStatus.get(this.status);
			if(desc == null){
				desc = "Unknown Status";
			}
			return String.format("HTTP/1.1 %s %s", status, desc); 
		}
		
		if(this.command != null){//command存在,则认为是请求元数据
			String cmdStr = encodeCommand();
			return String.format("%s /%s HTTP/1.1", method, cmdStr);
		}
		
		return "";
	}
	
	public Meta(){}
	
	public Meta(Meta m){
		this.command = m.command;
		this.method = m.method;
		this.status = m.status;
		if(m.params != null){
			this.params = new HashMap(m.params);
		}
	}
	
	public Meta(String meta){
		if("".equals(meta)){
			return;
		}
		StringTokenizer st = new StringTokenizer(meta);
		String method = st.nextToken();
		
		if(!httpMethod.contains(method)){ //不是method字段,理解为Response
			String status = st.nextToken();
			this.status = status;
			return;
		}
		
		this.method = method;  
		String commandString = st.nextToken();
		decodeCommand(commandString);
	} 
	

	private String encodeCommand(){
		StringBuilder sb = new StringBuilder();
		if(this.command != null){
			sb.append(this.command);
		}
		if(this.params == null) return sb.toString();
		
		Iterator> iter = this.params.entrySet().iterator();
		if(iter.hasNext()){
			sb.append("?");
		}
		
		while(iter.hasNext()){
			Entry e = iter.next();
			sb.append(e.getKey()+"="+e.getValue());
			if(iter.hasNext()){
				sb.append("&");
			}
		}
		return sb.toString();
	} 
	
	
	private void decodeCommand(String commandString){
		int idx = commandString.indexOf('?');
		if(idx < 0){
			this.command = decodeUrl(commandString);
		} else {
			this.command = commandString.substring(0, idx);
		}
		if(this.command.startsWith("/")){
			this.command = this.command.substring(1);
		}
		if(idx < 0) return;
		
		this.params = new HashMap(); 
		String paramString = commandString.substring(idx+1); 
		StringTokenizer st = new StringTokenizer(paramString, "&");
        while (st.hasMoreTokens()) {
            String e = st.nextToken();
            int sep = e.indexOf('=');
            if (sep >= 0) {
                this.params.put(decodeUrl(e.substring(0, sep)).trim(),
                		decodeUrl(e.substring(sep + 1)));
            } else {
                this.params.put(decodeUrl(e).trim(), "");
            }
        } 
	}
	
	private String decodeUrl(String str) {
        String decoded = null;
        try {
            decoded = URLDecoder.decode(str, "UTF8");
        } catch (UnsupportedEncodingException ignored) {
        }
        return decoded;
    }
	
	public String getParam(String key){
		if(params == null) return null;
		return params.get(key);
	}
	
	public String getParam(String key, String defaultValue){
		String value = getParam(key);
		if(value == null){
			value = defaultValue;
		}
		return value;
	}
	
	public void setParam(String key, String value){
		if(value == null) return;
		if(params == null){
			params = new HashMap();
		}
		params.put(key, value);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy