1
1
/*
2
- * Copyright 2002-2013 the original author or authors.
2
+ * Copyright 2002-2014 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
16
16
17
17
package org .springframework .messaging .simp .broker ;
18
18
19
- import java .util .Collection ;
20
- import java .util .HashSet ;
21
- import java .util .Map ;
22
- import java .util .Set ;
19
+ import java .util .*;
23
20
import java .util .concurrent .ConcurrentHashMap ;
24
21
import java .util .concurrent .ConcurrentMap ;
25
- import java .util .concurrent .CopyOnWriteArraySet ;
26
22
27
23
import org .springframework .messaging .Message ;
28
24
import org .springframework .util .AntPathMatcher ;
34
30
* A default, simple in-memory implementation of {@link SubscriptionRegistry}.
35
31
*
36
32
* @author Rossen Stoyanchev
33
+ * @author Sebastien Deleuze
37
34
* @since 4.0
38
35
*/
39
36
public class DefaultSubscriptionRegistry extends AbstractSubscriptionRegistry {
@@ -59,18 +56,16 @@ public AntPathMatcher getPathMatcher() {
59
56
@ Override
60
57
protected void addSubscriptionInternal (String sessionId , String subsId , String destination , Message <?> message ) {
61
58
SessionSubscriptionInfo info = this .subscriptionRegistry .addSubscription (sessionId , subsId , destination );
62
- if (!this .pathMatcher .isPattern (destination )) {
63
- this .destinationCache .mapToDestination (destination , info );
64
- }
59
+ this .destinationCache .mapToDestination (destination , sessionId , subsId );
65
60
}
66
61
67
62
@ Override
68
- protected void removeSubscriptionInternal (String sessionId , String subscriptionId , Message <?> message ) {
63
+ protected void removeSubscriptionInternal (String sessionId , String subsId , Message <?> message ) {
69
64
SessionSubscriptionInfo info = this .subscriptionRegistry .getSubscriptions (sessionId );
70
65
if (info != null ) {
71
- String destination = info .removeSubscription (subscriptionId );
66
+ String destination = info .removeSubscription (subsId );
72
67
if (info .getSubscriptions (destination ) == null ) {
73
- this .destinationCache .unmapFromDestination (destination , info );
68
+ this .destinationCache .unmapFromDestination (destination , sessionId , subsId );
74
69
}
75
70
}
76
71
}
@@ -88,8 +83,11 @@ public void unregisterAllSubscriptions(String sessionId) {
88
83
89
84
@ Override
90
85
protected MultiValueMap <String , String > findSubscriptionsInternal (String destination , Message <?> message ) {
91
- MultiValueMap <String ,String > result = this .destinationCache .getSubscriptions (destination );
92
- if (result .isEmpty ()) {
86
+ MultiValueMap <String ,String > result ;
87
+ if (this .destinationCache .isCachedDestination (destination )) {
88
+ result = this .destinationCache .getSubscriptions (destination );
89
+ }
90
+ else {
93
91
result = new LinkedMultiValueMap <String , String >();
94
92
for (SessionSubscriptionInfo info : this .subscriptionRegistry .getAllSubscriptions ()) {
95
93
for (String destinationPattern : info .getDestinations ()) {
@@ -100,6 +98,9 @@ protected MultiValueMap<String, String> findSubscriptionsInternal(String destina
100
98
}
101
99
}
102
100
}
101
+ if (!result .isEmpty ()) {
102
+ this .destinationCache .addSubscriptions (destination , result );
103
+ }
103
104
}
104
105
return result ;
105
106
}
@@ -114,60 +115,77 @@ public String toString() {
114
115
115
116
116
117
/**
117
- * Provide direct lookup of session subscriptions by destination (for non-pattern destinations).
118
+ * Provide direct lookup of session subscriptions by destination
118
119
*/
119
120
private static class DestinationCache {
120
121
122
+ private AntPathMatcher pathMatcher = new AntPathMatcher ();
123
+
121
124
// destination -> ..
122
- private final Map <String , Set < SessionSubscriptionInfo >> subscriptionsByDestination =
123
- new ConcurrentHashMap <String , Set < SessionSubscriptionInfo >>();
125
+ private final Map <String , MultiValueMap < String , String >> subscriptionsByDestination =
126
+ new ConcurrentHashMap <String , MultiValueMap < String , String >>();
124
127
125
128
private final Object monitor = new Object ();
126
129
127
130
128
- public void mapToDestination (String destination , SessionSubscriptionInfo info ) {
131
+ public void addSubscriptions (String destination , MultiValueMap <String , String > subscriptions ) {
132
+ this .subscriptionsByDestination .put (destination , subscriptions );
133
+ }
134
+
135
+ public void mapToDestination (String destination , String sessionId , String subsId ) {
129
136
synchronized (this .monitor ) {
130
- Set <SessionSubscriptionInfo > registrations = this .subscriptionsByDestination .get (destination );
131
- if (registrations == null ) {
132
- registrations = new CopyOnWriteArraySet <SessionSubscriptionInfo >();
133
- this .subscriptionsByDestination .put (destination , registrations );
137
+ for (String cachedDestination : this .subscriptionsByDestination .keySet ()) {
138
+ if (this .pathMatcher .match (destination , cachedDestination )) {
139
+ MultiValueMap <String , String > registrations = this .subscriptionsByDestination .get (cachedDestination );
140
+ if (registrations == null ) {
141
+ registrations = new LinkedMultiValueMap <String , String >();
142
+ }
143
+ registrations .add (sessionId , subsId );
144
+ }
134
145
}
135
- registrations .add (info );
136
146
}
137
147
}
138
148
139
- public void unmapFromDestination (String destination , SessionSubscriptionInfo info ) {
149
+ public void unmapFromDestination (String destination , String sessionId , String subsId ) {
140
150
synchronized (this .monitor ) {
141
- Set <SessionSubscriptionInfo > infos = this .subscriptionsByDestination .get (destination );
142
- if (infos != null ) {
143
- infos .remove (info );
144
- if (infos .isEmpty ()) {
145
- this .subscriptionsByDestination .remove (destination );
151
+ for (String cachedDestination : this .subscriptionsByDestination .keySet ()) {
152
+ if (this .pathMatcher .match (destination , cachedDestination )) {
153
+ MultiValueMap <String , String > registrations = this .subscriptionsByDestination .get (cachedDestination );
154
+ List <String > subscriptions = registrations .get (sessionId );
155
+ while (subscriptions .remove (subsId ));
156
+ if (subscriptions .isEmpty ()) {
157
+ registrations .remove (sessionId );
158
+ }
159
+ if (registrations .isEmpty ()) {
160
+ this .subscriptionsByDestination .remove (cachedDestination );
161
+ }
146
162
}
147
163
}
148
164
}
149
165
}
150
166
151
167
public void removeSessionSubscriptions (SessionSubscriptionInfo info ) {
152
- for (String destination : info .getDestinations ()) {
153
- unmapFromDestination (destination , info );
154
- }
155
- }
156
-
157
- public MultiValueMap <String , String > getSubscriptions (String destination ) {
158
- MultiValueMap <String , String > result = new LinkedMultiValueMap <String , String >();
159
- Set <SessionSubscriptionInfo > infos = this .subscriptionsByDestination .get (destination );
160
- if (infos != null ) {
161
- for (SessionSubscriptionInfo info : infos ) {
162
- Set <String > subscriptions = info .getSubscriptions (destination );
163
- if (subscriptions != null ) {
164
- for (String subscription : subscriptions ) {
165
- result .add (info .getSessionId (), subscription );
168
+ synchronized (this .monitor ) {
169
+ for (String destination : info .getDestinations ()) {
170
+ for (String cachedDestination : this .subscriptionsByDestination .keySet ()) {
171
+ if (this .pathMatcher .match (destination , cachedDestination )) {
172
+ MultiValueMap <String , String > map = this .subscriptionsByDestination .get (cachedDestination );
173
+ map .remove (info .getSessionId ());
174
+ if (map .isEmpty ()) {
175
+ this .subscriptionsByDestination .remove (cachedDestination );
176
+ }
166
177
}
167
178
}
168
179
}
169
180
}
170
- return result ;
181
+ }
182
+
183
+ public MultiValueMap <String , String > getSubscriptions (String destination ) {
184
+ return this .subscriptionsByDestination .get (destination );
185
+ }
186
+
187
+ public boolean isCachedDestination (String destination ) {
188
+ return subscriptionsByDestination .containsKey (destination );
171
189
}
172
190
173
191
@ Override
0 commit comments