1 /*
2  * Copyright 2002-2018 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 module hunt.stomp.support.GenericMessage;
18 
19 import hunt.stomp.Message;
20 import hunt.stomp.MessageHeaders;
21 
22 import hunt.collection.Map;
23 import hunt.text.Common;
24 import hunt.text.StringBuilder;
25 import hunt.util.ObjectUtils;
26 
27 
28 /**
29  * An implementation of {@link Message} with a generic payload.
30  * Once created, a GenericMessage is immutable.
31  *
32  * @author Mark Fisher
33  * @since 4.0
34  * @param (T) the payload type
35  * @see MessageBuilder
36  */
37 class GenericMessage(T) : Message!(T) {
38 
39 	private T payload;
40 
41 	private MessageHeaders headers;
42 
43 
44 	/**
45 	 * Create a new message with the given payload.
46 	 * @param payload the message payload (never {@code null})
47 	 */
48 	this(T payload) {
49 		this(payload, new MessageHeaders(null));
50 	}
51 
52 	/**
53 	 * Create a new message with the given payload and headers.
54 	 * The content of the given header map is copied.
55 	 * @param payload the message payload (never {@code null})
56 	 * @param headers message headers to use for initialization
57 	 */
58 	this(T payload, Map!(string, Object) headers) {
59 		this(payload, new MessageHeaders(headers));
60 	}
61 
62 	/**
63 	 * A constructor with the {@link MessageHeaders} instance to use.
64 	 * <p><strong>Note:</strong> the given {@code MessageHeaders} instance is used
65 	 * directly in the new message, i.e. it is not copied.
66 	 * @param payload the message payload (never {@code null})
67 	 * @param headers message headers
68 	 */
69 	this(T payload, MessageHeaders headers) {
70 		// assert(payload, "Payload must not be null");
71 		assert(headers, "MessageHeaders must not be null");
72 		this.payload = payload;
73 		this.headers = headers;
74 	}
75 
76 	TypeInfo payloadType() {
77 		return typeid(T);
78 	}
79 
80 	T getPayload() {
81 		return this.payload;
82 	}
83 
84 	MessageHeaders getHeaders() {
85 		return this.headers;
86 	}
87 
88 	override bool opEquals(Object other) {
89 		if (this is other) {
90 			return true;
91 		}
92 
93 		GenericMessage!T otherMsg = cast(GenericMessage!T) other;
94 		if (otherMsg is null) {
95 			return false;
96 		}
97 		return this.payload == otherMsg.payload && this.headers == otherMsg.headers;
98 	}
99 
100 	override size_t toHash() @trusted nothrow {
101 		// Using nullSafeHashCode for proper array toHash handling
102 		return hashOf(this.payload) * 23 + this.headers.toHash();
103 	}
104 
105 	override string toString() {
106 		StringBuilder sb = new StringBuilder(typeid(this).name);
107 		sb.append(" [payload=");
108 		static if(is(T == class)) {
109 			sb.append(this.payload.toString());
110 		} else static if(is(T == interface)) {
111 			sb.append((cast(Object)this.payload).toString());
112 		} else {
113 			sb.append("byte[").append((cast(byte[]) this.payload).length).append("]");
114 		}
115 		// static if(is(T == byte[])) {
116 		// 	sb.append("byte[").append((cast(byte[]) this.payload).length).append("]");
117 		// } else {
118 		// 	sb.append(this.payload.toString());
119 		// }
120 		sb.append(", headers=").append(this.headers.toString()).append("]");
121 		return sb.toString();
122 	}
123 
124 }