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.simp.annotation.SendToMethodReturnValueHandler; 18 19 // import java.lang.annotation.Annotation; 20 // import hunt.security.Principal; 21 // import hunt.collection.Collections; 22 // import hunt.collection.Map; 23 24 // import hunt.framework.core.MethodParameter; 25 // import hunt.framework.core.annotation.AnnotatedElementUtils; 26 // import hunt.framework.core.annotation.AnnotationUtils; 27 28 // import hunt.stomp.Message; 29 // import hunt.stomp.MessageChannel; 30 // import hunt.stomp.MessageHeaders; 31 // import hunt.stomp.handler.DestinationPatternsMessageCondition; 32 // import hunt.stomp.handler.annotation.SendTo; 33 // import hunt.stomp.handler.annotation.support.DestinationVariableMethodArgumentResolver; 34 // import hunt.stomp.handler.invocation.HandlerMethodReturnValueHandler; 35 // import hunt.stomp.simp.SimpMessageHeaderAccessor; 36 // import hunt.stomp.simp.SimpMessageSendingOperations; 37 // import hunt.stomp.simp.SimpMessageType; 38 // import hunt.stomp.simp.SimpMessagingTemplate; 39 // import hunt.stomp.simp.annotation.SendToUser; 40 // import hunt.stomp.simp.user.DestinationUserNameProvider; 41 // 42 43 // import hunt.framework.util.ObjectUtils; 44 // import hunt.framework.util.PropertyPlaceholderHelper; 45 // import hunt.framework.util.PropertyPlaceholderHelper.PlaceholderResolver; 46 // import hunt.framework.util.StringUtils; 47 48 // /** 49 // * A {@link HandlerMethodReturnValueHandler} for sending to destinations specified in a 50 // * {@link SendTo} or {@link SendToUser} method-level annotations. 51 // * 52 // * <p>The value returned from the method is converted, and turned to a {@link Message} and 53 // * sent through the provided {@link MessageChannel}. The message is then enriched with the 54 // * session id of the input message as well as the destination from the annotation(s). 55 // * If multiple destinations are specified, a copy of the message is sent to each destination. 56 // * 57 // * @author Rossen Stoyanchev 58 // * @author Sebastien Deleuze 59 // * @since 4.0 60 // */ 61 // class SendToMethodReturnValueHandler : HandlerMethodReturnValueHandler { 62 63 // private SimpMessageSendingOperations messagingTemplate; 64 65 // private bool annotationRequired; 66 67 // private string defaultDestinationPrefix = "/topic"; 68 69 // private string defaultUserDestinationPrefix = "/queue"; 70 71 // private PropertyPlaceholderHelper placeholderHelper; 72 73 // private MessageHeaderInitializer headerInitializer; 74 75 76 // this(SimpMessageSendingOperations messagingTemplate, bool annotationRequired) { 77 // assert(messagingTemplate, "'messagingTemplate' must not be null"); 78 // this.messagingTemplate = messagingTemplate; 79 // this.annotationRequired = annotationRequired; 80 // placeholderHelper = new PropertyPlaceholderHelper("{", "}", null, false); 81 // } 82 83 84 // /** 85 // * Configure a default prefix to add to message destinations in cases where a method 86 // * is not annotated with {@link SendTo @SendTo} or does not specify any destinations 87 // * through the annotation's value attribute. 88 // * <p>By default, the prefix is set to "/topic". 89 // */ 90 // void setDefaultDestinationPrefix(string defaultDestinationPrefix) { 91 // this.defaultDestinationPrefix = defaultDestinationPrefix; 92 // } 93 94 // /** 95 // * Return the configured default destination prefix. 96 // * @see #setDefaultDestinationPrefix(string) 97 // */ 98 // string getDefaultDestinationPrefix() { 99 // return this.defaultDestinationPrefix; 100 // } 101 102 // /** 103 // * Configure a default prefix to add to message destinations in cases where a 104 // * method is annotated with {@link SendToUser @SendToUser} but does not specify 105 // * any destinations through the annotation's value attribute. 106 // * <p>By default, the prefix is set to "/queue". 107 // */ 108 // void setDefaultUserDestinationPrefix(string prefix) { 109 // this.defaultUserDestinationPrefix = prefix; 110 // } 111 112 // /** 113 // * Return the configured default user destination prefix. 114 // * @see #setDefaultUserDestinationPrefix(string) 115 // */ 116 // string getDefaultUserDestinationPrefix() { 117 // return this.defaultUserDestinationPrefix; 118 // } 119 120 // /** 121 // * Configure a {@link MessageHeaderInitializer} to apply to the headers of all 122 // * messages sent to the client outbound channel. 123 // * <p>By default this property is not set. 124 // */ 125 // void setHeaderInitializer(MessageHeaderInitializer headerInitializer) { 126 // this.headerInitializer = headerInitializer; 127 // } 128 129 // /** 130 // * Return the configured header initializer. 131 // */ 132 133 // MessageHeaderInitializer getHeaderInitializer() { 134 // return this.headerInitializer; 135 // } 136 137 138 // override 139 // bool supportsReturnType(MethodParameter returnType) { 140 // return (returnType.hasMethodAnnotation(SendTo.class) || 141 // AnnotatedElementUtils.hasAnnotation(returnType.getDeclaringClass(), SendTo.class) || 142 // returnType.hasMethodAnnotation(SendToUser.class) || 143 // AnnotatedElementUtils.hasAnnotation(returnType.getDeclaringClass(), SendToUser.class) || 144 // !this.annotationRequired); 145 // } 146 147 // override 148 // void handleReturnValue(Object returnValue, MethodParameter returnType, MessageBase message) { 149 150 // if (returnValue is null) { 151 // return; 152 // } 153 154 // MessageHeaders headers = message.getHeaders(); 155 // string sessionId = SimpMessageHeaderAccessor.getSessionId(headers); 156 // DestinationHelper destinationHelper = getDestinationHelper(headers, returnType); 157 158 // SendToUser sendToUser = destinationHelper.getSendToUser(); 159 // if (sendToUser !is null) { 160 // broadcast = sendToUser.broadcast(); 161 // string user = getUserName(message, headers); 162 // if (user is null) { 163 // if (sessionId is null) { 164 // throw new MissingSessionUserException(message); 165 // } 166 // user = sessionId; 167 // broadcast = false; 168 // } 169 // string[] destinations = getTargetDestinations(sendToUser, message, this.defaultUserDestinationPrefix); 170 // for (string destination : destinations) { 171 // destination = destinationHelper.expandTemplateVars(destination); 172 // if (broadcast) { 173 // this.messagingTemplate.convertAndSendToUser( 174 // user, destination, returnValue, createHeaders(null, returnType)); 175 // } 176 // else { 177 // this.messagingTemplate.convertAndSendToUser( 178 // user, destination, returnValue, createHeaders(sessionId, returnType)); 179 // } 180 // } 181 // } 182 183 // SendTo sendTo = destinationHelper.getSendTo(); 184 // if (sendTo !is null || sendToUser is null) { 185 // string[] destinations = getTargetDestinations(sendTo, message, this.defaultDestinationPrefix); 186 // for (string destination : destinations) { 187 // destination = destinationHelper.expandTemplateVars(destination); 188 // this.messagingTemplate.convertAndSend(destination, returnValue, createHeaders(sessionId, returnType)); 189 // } 190 // } 191 // } 192 193 // private DestinationHelper getDestinationHelper(MessageHeaders headers, MethodParameter returnType) { 194 // SendToUser m1 = AnnotatedElementUtils.findMergedAnnotation(returnType.getExecutable(), SendToUser.class); 195 // SendTo m2 = AnnotatedElementUtils.findMergedAnnotation(returnType.getExecutable(), SendTo.class); 196 // if ((m1 !is null && !ObjectUtils.isEmpty(m1.value())) || (m2 !is null && !ObjectUtils.isEmpty(m2.value()))) { 197 // return new DestinationHelper(headers, m1, m2); 198 // } 199 200 // SendToUser c1 = AnnotatedElementUtils.findMergedAnnotation(returnType.getDeclaringClass(), SendToUser.class); 201 // SendTo c2 = AnnotatedElementUtils.findMergedAnnotation(returnType.getDeclaringClass(), SendTo.class); 202 // if ((c1 !is null && !ObjectUtils.isEmpty(c1.value())) || (c2 !is null && !ObjectUtils.isEmpty(c2.value()))) { 203 // return new DestinationHelper(headers, c1, c2); 204 // } 205 206 // return (m1 !is null || m2 !is null ? 207 // new DestinationHelper(headers, m1, m2) : new DestinationHelper(headers, c1, c2)); 208 // } 209 210 211 // protected string getUserName(MessageBase message, MessageHeaders headers) { 212 // Principal principal = SimpMessageHeaderAccessor.getUser(headers); 213 // if (principal !is null) { 214 // return (principal instanceof DestinationUserNameProvider ? 215 // ((DestinationUserNameProvider) principal).getDestinationUserName() : principal.getName()); 216 // } 217 // return null; 218 // } 219 220 // protected string[] getTargetDestinations(Annotation annotation, MessageBase message, string defaultPrefix) { 221 // if (annotation !is null) { 222 // string[] value = (string[]) AnnotationUtils.getValue(annotation); 223 // if (!ObjectUtils.isEmpty(value)) { 224 // return value; 225 // } 226 // } 227 228 // string name = DestinationPatternsMessageCondition.LOOKUP_DESTINATION_HEADER; 229 // string destination = (string) message.getHeaders().get(name); 230 // if (!StringUtils.hasText(destination)) { 231 // throw new IllegalStateException("No lookup destination header in " ~ message); 232 // } 233 234 // return (destination.startsWith("/") ? 235 // new string[] {defaultPrefix + destination} : new string[] {defaultPrefix + '/' + destination}); 236 // } 237 238 // private MessageHeaders createHeaders(string sessionId, MethodParameter returnType) { 239 // SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE); 240 // if (getHeaderInitializer() !is null) { 241 // getHeaderInitializer().initHeaders(headerAccessor); 242 // } 243 // if (sessionId !is null) { 244 // headerAccessor.setSessionId(sessionId); 245 // } 246 // headerAccessor.setHeader(SimpMessagingTemplate.CONVERSION_HINT_HEADER, returnType); 247 // headerAccessor.setLeaveMutable(true); 248 // return headerAccessor.getMessageHeaders(); 249 // } 250 251 252 // override 253 // string toString() { 254 // return "SendToMethodReturnValueHandler [annotationRequired=" ~ this.annotationRequired ~ "]"; 255 // } 256 257 258 // private class DestinationHelper { 259 260 // private final PlaceholderResolver placeholderResolver; 261 262 263 // private final SendTo sendTo; 264 265 266 // private final SendToUser sendToUser; 267 268 269 // DestinationHelper(MessageHeaders headers, SendToUser sendToUser, SendTo sendTo) { 270 // Map!(string, string) variables = getTemplateVariables(headers); 271 // this.placeholderResolver = variables::get; 272 // this.sendTo = sendTo; 273 // this.sendToUser = sendToUser; 274 // } 275 276 277 // private Map!(string, string) getTemplateVariables(MessageHeaders headers) { 278 // string name = DestinationVariableMethodArgumentResolver.DESTINATION_TEMPLATE_VARIABLES_HEADER; 279 // return (Map!(string, string)) headers.getOrDefault(name, Collections.emptyMap()); 280 // } 281 282 283 // SendTo getSendTo() { 284 // return this.sendTo; 285 // } 286 287 288 // SendToUser getSendToUser() { 289 // return this.sendToUser; 290 // } 291 292 // string expandTemplateVars(string destination) { 293 // return placeholderHelper.replacePlaceholders(destination, this.placeholderResolver); 294 // } 295 // } 296 297 // }