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 }