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.config.MessageBrokerRegistry;
18 
19 // import hunt.framework.context.event.SmartApplicationListener;
20 import hunt.stomp.simp.config.ChannelRegistration;
21 import hunt.stomp.simp.config.StompBrokerRelayRegistration;
22 import hunt.stomp.simp.config.SimpleBrokerRegistration;
23 
24 
25 import hunt.stomp.MessageChannel;
26 import hunt.stomp.simp.broker.SimpleBrokerMessageHandler;
27 import hunt.stomp.simp.stomp.StompBrokerRelayMessageHandler;
28 
29 import hunt.text.PathMatcher;
30 
31 /**
32  * A registry for configuring message broker options.
33  *
34  * @author Rossen Stoyanchev
35  * @author Sebastien Deleuze
36  * @since 4.0
37  */
38 class MessageBrokerRegistry {
39 
40 	private SubscribableChannel clientInboundChannel;
41 
42 	private MessageChannel clientOutboundChannel;
43 	
44 	private SimpleBrokerRegistration simpleBrokerRegistration;
45 	
46 	private StompBrokerRelayRegistration brokerRelayRegistration;
47 
48 	private ChannelRegistration brokerChannelRegistration;
49 	
50 	private string[] applicationDestinationPrefixes;
51 	
52 	private string userDestinationPrefix;
53 	
54 	private int userRegistryOrder;
55 
56 	private PathMatcher pathMatcher;
57 	
58 	private int cacheLimit;
59 
60 	private bool preservePublishOrder;
61 
62 
63 	this(SubscribableChannel clientInboundChannel, MessageChannel clientOutboundChannel) {
64 		assert(clientInboundChannel, "Inbound channel must not be null");
65 		assert(clientOutboundChannel, "Outbound channel must not be null");
66 
67 		brokerChannelRegistration = new ChannelRegistration();
68 		this.clientInboundChannel = clientInboundChannel;
69 		this.clientOutboundChannel = clientOutboundChannel;
70 	}
71 
72 
73 	/**
74 	 * Enable a simple message broker and configure one or more prefixes to filter
75 	 * destinations targeting the broker (e.g. destinations prefixed with "/topic").
76 	 */
77 	SimpleBrokerRegistration enableSimpleBroker(string[] destinationPrefixes... ) {
78 		this.simpleBrokerRegistration = new SimpleBrokerRegistration(
79 				this.clientInboundChannel, this.clientOutboundChannel, destinationPrefixes.dup);
80 		return this.simpleBrokerRegistration;
81 	}
82 
83 	/**
84 	 * Enable a STOMP broker relay and configure the destination prefixes supported by the
85 	 * message broker. Check the STOMP documentation of the message broker for supported
86 	 * destinations.
87 	 */
88 	StompBrokerRelayRegistration enableStompBrokerRelay(string[] destinationPrefixes... ) {
89 		this.brokerRelayRegistration = new StompBrokerRelayRegistration(
90 				this.clientInboundChannel, this.clientOutboundChannel, destinationPrefixes.dup);
91 		return this.brokerRelayRegistration;
92 	}
93 
94 	/**
95 	 * Customize the channel used to send messages from the application to the message
96 	 * broker. By default, messages from the application to the message broker are sent
97 	 * synchronously, which means application code sending a message will find out
98 	 * if the message cannot be sent through an exception. However, this can be changed
99 	 * if the broker channel is configured here with task executor properties.
100 	 */
101 	ChannelRegistration configureBrokerChannel() {
102 		return this.brokerChannelRegistration;
103 	}
104 
105 	ChannelRegistration getBrokerChannelRegistration() {
106 		return this.brokerChannelRegistration;
107 	}
108 
109 	
110 	string getUserDestinationBroadcast() {
111 		return (this.brokerRelayRegistration !is null ?
112 				this.brokerRelayRegistration.getUserDestinationBroadcast() : null);
113 	}
114 
115 	
116 	string getUserRegistryBroadcast() {
117 		return (this.brokerRelayRegistration !is null ?
118 				this.brokerRelayRegistration.getUserRegistryBroadcast() : null);
119 	}
120 
121 	/**
122 	 * Configure one or more prefixes to filter destinations targeting application
123 	 * annotated methods. For example destinations prefixed with "/app" may be
124 	 * processed by annotated methods while other destinations may target the
125 	 * message broker (e.g. "/topic", "/queue").
126 	 * <p>When messages are processed, the matching prefix is removed from the destination
127 	 * in order to form the lookup path. This means annotations should not contain the
128 	 * destination prefix.
129 	 * <p>Prefixes that do not have a trailing slash will have one automatically appended.
130 	 */
131 	MessageBrokerRegistry setApplicationDestinationPrefixes(string[] prefixes... ) {
132 		this.applicationDestinationPrefixes = prefixes.dup;
133 		return this;
134 	}
135 
136 	
137 	string[] getApplicationDestinationPrefixes() {
138 		return (this.applicationDestinationPrefixes !is null ?
139 				this.applicationDestinationPrefixes : null);
140 	}
141 
142 	/**
143 	 * Configure the prefix used to identify user destinations. User destinations
144 	 * provide the ability for a user to subscribe to queue names unique to their
145 	 * session as well as for others to send messages to those unique,
146 	 * user-specific queues.
147 	 * <p>For example when a user attempts to subscribe to "/user/queue/position-updates",
148 	 * the destination may be translated to "/queue/position-updatesi9oqdfzo" yielding a
149 	 * unique queue name that does not collide with any other user attempting to do the same.
150 	 * Subsequently when messages are sent to "/user/{username}/queue/position-updates",
151 	 * the destination is translated to "/queue/position-updatesi9oqdfzo".
152 	 * <p>The default prefix used to identify such destinations is "/user/".
153 	 */
154 	MessageBrokerRegistry setUserDestinationPrefix(string destinationPrefix) {
155 		this.userDestinationPrefix = destinationPrefix;
156 		return this;
157 	}
158 
159 	
160 	string getUserDestinationPrefix() {
161 		return this.userDestinationPrefix;
162 	}
163 
164 	/**
165 	 * Set the order for the
166 	 * {@link hunt.stomp.simp.user.SimpUserRegistry
167 	 * SimpUserRegistry} to use as a {@link SmartApplicationListener}.
168 	 * @param order the order value
169 	 * @since 5.0.8
170 	 */
171 	void setUserRegistryOrder(int order) {
172 		this.userRegistryOrder = order;
173 	}
174 
175 	
176 	int getUserRegistryOrder() {
177 		return this.userRegistryOrder;
178 	}
179 
180 	/**
181 	 * Configure the PathMatcher to use to match the destinations of incoming
182 	 * messages to {@code @MessageMapping} and {@code @SubscribeMapping} methods.
183 	 * <p>By default {@link hunt.framework.util.AntPathMatcher} is configured.
184 	 * However applications may provide an {@code AntPathMatcher} instance
185 	 * customized to use "." (commonly used in messaging) instead of "/" as path
186 	 * separator or provide a completely different PathMatcher implementation.
187 	 * <p>Note that the configured PathMatcher is only used for matching the
188 	 * portion of the destination after the configured prefix. For example given
189 	 * application destination prefix "/app" and destination "/app/price.stock.**",
190 	 * the message might be mapped to a controller with "price" and "stock.**"
191 	 * as its type and method-level mappings respectively.
192 	 * <p>When the simple broker is enabled, the PathMatcher configured here is
193 	 * also used to match message destinations when brokering messages.
194 	 * @since 4.1
195 	 * @see hunt.stomp.simp.broker.DefaultSubscriptionRegistry#setPathMatcher
196 	 */
197 	MessageBrokerRegistry setPathMatcher(PathMatcher pathMatcher) {
198 		this.pathMatcher = pathMatcher;
199 		return this;
200 	}
201 
202 	
203 	PathMatcher getPathMatcher() {
204 		return this.pathMatcher;
205 	}
206 
207 	/**
208 	 * Configure the cache limit to apply for registrations with the broker.
209 	 * <p>This is currently only applied for the destination cache in the
210 	 * subscription registry. The default cache limit there is 1024.
211 	 * @since 4.3.2
212 	 * @see hunt.stomp.simp.broker.DefaultSubscriptionRegistry#setCacheLimit
213 	 */
214 	MessageBrokerRegistry setCacheLimit(int cacheLimit) {
215 		this.cacheLimit = cacheLimit;
216 		return this;
217 	}
218 
219 	/**
220 	 * Whether the client must receive messages in the order of publication.
221 	 * <p>By default messages sent to the {@code "clientOutboundChannel"} may
222 	 * not be processed in the same order because the channel is backed by a
223 	 * ThreadPoolExecutor that in turn does not guarantee processing in order.
224 	 * <p>When this flag is set to {@code true} messages within the same session
225 	 * will be sent to the {@code "clientOutboundChannel"} one at a time in
226 	 * order to preserve the order of publication. Enable this only if needed
227 	 * since there is some performance overhead to keep messages in order.
228 	 * @since 5.1
229 	 */
230 	MessageBrokerRegistry setPreservePublishOrder(bool preservePublishOrder) {
231 		this.preservePublishOrder = preservePublishOrder;
232 		return this;
233 	}
234 
235 	
236 	SimpleBrokerMessageHandler getSimpleBroker(SubscribableChannel brokerChannel) {
237 		if (this.simpleBrokerRegistration is null && this.brokerRelayRegistration is null) {
238 			enableSimpleBroker();
239 		}
240 		if (this.simpleBrokerRegistration !is null) {
241 			SimpleBrokerMessageHandler handler = this.simpleBrokerRegistration.getMessageHandler(brokerChannel);
242 			handler.setPathMatcher(this.pathMatcher);
243 			handler.setCacheLimit(this.cacheLimit);
244 			handler.setPreservePublishOrder(this.preservePublishOrder);
245 			return handler;
246 		}
247 		return null;
248 	}
249 
250 	
251 	// StompBrokerRelayMessageHandler getStompBrokerRelay(SubscribableChannel brokerChannel) {
252 	// 	if (this.brokerRelayRegistration !is null) {
253 	// 		StompBrokerRelayMessageHandler relay = this.brokerRelayRegistration.getMessageHandler(brokerChannel);
254 	// 		relay.setPreservePublishOrder(this.preservePublishOrder);
255 	// 		return relay;
256 	// 	}
257 	// 	return null;
258 	// }
259 
260 }