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 // }