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.NativeMessageHeaderAccessor; 18 19 import hunt.stomp.support.MessageHeaderAccessor; 20 import hunt.stomp.Message; 21 22 import hunt.collection; 23 import hunt.util.ObjectUtils; 24 25 // 26 // import hunt.framework.util.CollectionUtils; 27 // import hunt.framework.util.LinkedMultiValueMap; 28 // import hunt.framework.util.MultiValueMap; 29 // import hunt.util.ObjectUtils; 30 31 32 33 34 /** 35 * An extension of {@link MessageHeaderAccessor} that also stores and provides read/write 36 * access to message headers from an external source -- e.g. a Spring {@link Message} 37 * created to represent a STOMP message received from a STOMP client or message broker. 38 * Native message headers are kept in a {@code MultiStringsMap} under the key 39 * {@link #NATIVE_HEADERS}. 40 * 41 * <p>This class is not intended for direct use but is rather expected to be used 42 * indirectly through protocol-specific sub-classes such as 43 * {@link hunt.stomp.simp.stomp.StompHeaderAccessor StompHeaderAccessor}. 44 * Such sub-classes may provide factory methods to translate message headers from 45 * an external messaging source (e.g. STOMP) to Spring {@link Message} headers and 46 * reversely to translate Spring {@link Message} headers to a message to send to an 47 * external source. 48 * 49 * @author Rossen Stoyanchev 50 * @since 4.0 51 */ 52 class NativeMessageHeaderAccessor : MessageHeaderAccessor { 53 54 /** 55 * The header name used to store native headers. 56 */ 57 enum string NATIVE_HEADERS = "nativeHeaders"; 58 59 60 /** 61 * A protected constructor to create new headers. 62 */ 63 protected this() { 64 this(cast(MultiStringsMap) null); 65 } 66 67 /** 68 * A protected constructor to create new headers. 69 * @param nativeHeaders native headers to create the message with (may be {@code null}) 70 */ 71 protected this(MultiStringsMap nativeHeaders) { 72 if (nativeHeaders !is null && nativeHeaders.size() > 0) { 73 setHeader(NATIVE_HEADERS, new LinkedMultiValueMap!(string, string)(nativeHeaders)); 74 } 75 } 76 77 /** 78 * A protected constructor accepting the headers of an existing message to copy. 79 */ 80 protected this(MessageBase message) { 81 super(message); 82 if (message !is null) { 83 84 MultiStringsMap map = cast(MultiStringsMap) getHeader(NATIVE_HEADERS); 85 if (map !is null) { 86 // Force removal since setHeader checks for equality 87 removeHeader(NATIVE_HEADERS); 88 setHeader(NATIVE_HEADERS, new LinkedMultiValueMap!(string, string)(map)); 89 } 90 } 91 } 92 93 94 95 protected MultiStringsMap getNativeHeaders() { 96 return cast(MultiStringsMap) getHeader(NATIVE_HEADERS); 97 } 98 99 /** 100 * Return a copy of the native header values or an empty map. 101 */ 102 MultiStringsMap toNativeHeaderMap() { 103 MultiStringsMap map = getNativeHeaders(); 104 return (map !is null ? new LinkedMultiValueMap!(string, string)(map) : 105 Collections.emptyMap!(string, List!(string))()); 106 } 107 108 override 109 void setImmutable() { 110 if (isMutable()) { 111 MultiStringsMap map = getNativeHeaders(); 112 if (map !is null) { 113 // Force removal since setHeader checks for equality 114 removeHeader(NATIVE_HEADERS); 115 setHeader(NATIVE_HEADERS, cast(Object)map); 116 // setHeader(NATIVE_HEADERS, Collections.unmodifiableMap(map)); 117 } 118 super.setImmutable(); 119 } 120 } 121 122 /** 123 * Whether the native header map contains the give header name. 124 */ 125 bool containsNativeHeader(string headerName) { 126 MultiStringsMap map = getNativeHeaders(); 127 return (map !is null && map.containsKey(headerName)); 128 } 129 130 /** 131 * Return all values for the specified native header. 132 * or {@code null} if none. 133 */ 134 135 List!(string) getNativeHeader(string headerName) { 136 MultiStringsMap map = getNativeHeaders(); 137 return (map !is null ? map.get(headerName) : null); 138 } 139 140 /** 141 * Return the first value for the specified native header, 142 * or {@code null} if none. 143 */ 144 145 string getFirstNativeHeader(string headerName) { 146 MultiStringsMap map = getNativeHeaders(); 147 if (map !is null) { 148 List!(string) values = map.get(headerName); 149 if (values !is null) { 150 return values.get(0); 151 } 152 } 153 return null; 154 } 155 156 /** 157 * Set the specified native header value replacing existing values. 158 */ 159 void setNativeHeader(string name, string value) { 160 assert(isMutable(), "Already immutable"); 161 MultiStringsMap map = getNativeHeaders(); 162 if (value is null) { 163 if (map !is null && map.get(name) !is null) { 164 setModified(true); 165 map.remove(name); 166 } 167 return; 168 } 169 if (map is null) { 170 map = new LinkedMultiValueMap!(string, string)(4); 171 setHeader(NATIVE_HEADERS, cast(Object)map); 172 } 173 List!(string) values = new LinkedList!(string)(); 174 values.add(value); 175 if (!ObjectUtils.nullSafeEquals(cast(Object)values, getHeader(name))) { 176 setModified(true); 177 map.put(name, values); 178 } 179 } 180 181 /** 182 * Add the specified native header value to existing values. 183 */ 184 void addNativeHeader(string name, string value) { 185 assert(isMutable(), "Already immutable"); 186 if (value is null) { 187 return; 188 } 189 MultiStringsMap nativeHeaders = getNativeHeaders(); 190 if (nativeHeaders is null) { 191 nativeHeaders = new LinkedMultiValueMap!(string, string)(4); 192 setHeader(NATIVE_HEADERS, cast(Object)nativeHeaders); 193 } 194 List!(string) values = nativeHeaders.computeIfAbsent(name, k => new LinkedList!(string)()); 195 values.add(value); 196 setModified(true); 197 } 198 199 void addNativeHeaders(MultiValueMap!(string, string) headers) { 200 if (headers is null) { 201 return; 202 } 203 foreach(string key, List!(string) values; headers) { 204 foreach(string value; values) { 205 addNativeHeader(key, value); 206 } 207 } 208 } 209 210 211 List!(string) removeNativeHeader(string name) { 212 assert(isMutable(), "Already immutable"); 213 MultiStringsMap nativeHeaders = getNativeHeaders(); 214 if (nativeHeaders is null) { 215 return null; 216 } 217 return nativeHeaders.remove(name); 218 } 219 220 221 222 static string getFirstNativeHeader(string headerName, Map!(string, Object) headers) { 223 MultiStringsMap map = cast(MultiStringsMap) headers.get(NATIVE_HEADERS); 224 if (map !is null) { 225 List!(string) values = map.get(headerName); 226 if (values !is null) { 227 return values.get(0); 228 } 229 } 230 return null; 231 } 232 233 }