19
19
import java .util .Collections ;
20
20
21
21
import org .springframework .http .server .PathContainer ;
22
+ import org .springframework .lang .Nullable ;
22
23
import org .springframework .messaging .Message ;
23
24
import org .springframework .messaging .simp .SimpMessageHeaderAccessor ;
24
25
import org .springframework .messaging .simp .SimpMessageType ;
26
+ import org .springframework .security .messaging .access .intercept .MessageAuthorizationContext ;
25
27
import org .springframework .util .Assert ;
26
28
import org .springframework .web .util .pattern .PathPattern ;
27
29
import org .springframework .web .util .pattern .PathPatternParser ;
@@ -40,16 +42,16 @@ public final class PathPatternMessageMatcher implements MessageMatcher<Object> {
40
42
41
43
private final PathPattern pattern ;
42
44
43
- private final PathPatternParser parser ;
45
+ private final PathContainer . Options options ;
44
46
45
47
/**
46
48
* The {@link MessageMatcher} that determines if the type matches. If the type was
47
49
* null, this matcher will match every Message.
48
50
*/
49
51
private MessageMatcher <Object > messageTypeMatcher = ANY_MESSAGE ;
50
52
51
- private PathPatternMessageMatcher (PathPattern pattern , PathPatternParser parser ) {
52
- this .parser = parser ;
53
+ private PathPatternMessageMatcher (PathPattern pattern , PathContainer . Options options ) {
54
+ this .options = options ;
53
55
this .pattern = pattern ;
54
56
}
55
57
@@ -78,17 +80,7 @@ void setMessageTypeMatcher(MessageMatcher<Object> messageTypeMatcher) {
78
80
*/
79
81
@ Override
80
82
public boolean matches (Message <?> message ) {
81
- if (!this .messageTypeMatcher .matches (message )) {
82
- return false ;
83
- }
84
-
85
- String destination = getDestination (message );
86
- if (destination == null ) {
87
- return false ;
88
- }
89
-
90
- PathContainer destinationPathContainer = PathContainer .parsePath (destination , this .parser .getPathOptions ());
91
- return this .pattern .matches (destinationPathContainer );
83
+ return matcher (message ).isMatch ();
92
84
}
93
85
94
86
/**
@@ -109,7 +101,7 @@ public MatchResult matcher(Message<?> message) {
109
101
return MatchResult .notMatch ();
110
102
}
111
103
112
- PathContainer destinationPathContainer = PathContainer .parsePath (destination , this .parser . getPathOptions () );
104
+ PathContainer destinationPathContainer = PathContainer .parsePath (destination , this .options );
113
105
PathPattern .PathMatchInfo pathMatchInfo = this .pattern .matchAndExtract (destinationPathContainer );
114
106
115
107
return (pathMatchInfo != null ) ? MatchResult .match (pathMatchInfo .getUriVariables ()) : MatchResult .notMatch ();
@@ -119,33 +111,92 @@ private static String getDestination(Message<?> message) {
119
111
return SimpMessageHeaderAccessor .getDestination (message .getHeaders ());
120
112
}
121
113
114
+ /**
115
+ * A builder for specifying various elements of a message for the purpose of creating
116
+ * a {@link PathPatternMessageMatcher}.
117
+ */
122
118
public static class Builder {
123
119
124
120
private final PathPatternParser parser ;
125
121
126
- private MessageMatcher <Object > messageTypeMatcher = ANY_MESSAGE ;
127
-
128
122
Builder (PathPatternParser parser ) {
129
123
this .parser = parser ;
130
124
}
131
125
126
+ /**
127
+ * Match messages having this destination pattern.
128
+ *
129
+ * <p>
130
+ * Path patterns always start with a slash and may contain placeholders. They can
131
+ * also be followed by {@code /**} to signify all URIs under a given path.
132
+ *
133
+ * <p>
134
+ * The following are valid patterns and their meaning
135
+ * <ul>
136
+ * <li>{@code /path} - match exactly and only `/path`</li>
137
+ * <li>{@code /path/**} - match `/path` and any of its descendents</li>
138
+ * <li>{@code /path/{value}/**} - match `/path/subdirectory` and any of its
139
+ * descendents, capturing the value of the subdirectory in
140
+ * {@link MessageAuthorizationContext#getVariables()}</li>
141
+ * </ul>
142
+ *
143
+ * <p>
144
+ * A more comprehensive list can be found at {@link PathPattern}.
145
+ *
146
+ * <p>
147
+ * A dot-based message pattern is also supported when configuring a
148
+ * {@link PathPatternParser} using
149
+ * {@link PathPatternMessageMatcher#withPathPatternParser}
150
+ * @param pattern the destination pattern to match
151
+ * @return the {@link PathPatternMessageMatcher.Builder} for more configuration
152
+ */
132
153
public PathPatternMessageMatcher matcher (String pattern ) {
133
- Assert .notNull (pattern , "Pattern must not be null" );
154
+ return matcher (null , pattern );
155
+ }
156
+
157
+ /**
158
+ * Match messages having this type and destination pattern.
159
+ *
160
+ * <p>
161
+ * When the message {@code type} is null, then the matcher does not consider the
162
+ * message type
163
+ *
164
+ * <p>
165
+ * Path patterns always start with a slash and may contain placeholders. They can
166
+ * also be followed by {@code /**} to signify all URIs under a given path.
167
+ *
168
+ * <p>
169
+ * The following are valid patterns and their meaning
170
+ * <ul>
171
+ * <li>{@code /path} - match exactly and only `/path`</li>
172
+ * <li>{@code /path/**} - match `/path` and any of its descendents</li>
173
+ * <li>{@code /path/{value}/**} - match `/path/subdirectory` and any of its
174
+ * descendents, capturing the value of the subdirectory in
175
+ * {@link MessageAuthorizationContext#getVariables()}</li>
176
+ * </ul>
177
+ *
178
+ * <p>
179
+ * A more comprehensive list can be found at {@link PathPattern}.
180
+ *
181
+ * <p>
182
+ * A dot-based message pattern is also supported when configuring a
183
+ * {@link PathPatternParser} using
184
+ * {@link PathPatternMessageMatcher#withPathPatternParser}
185
+ * @param type the message type to match
186
+ * @param pattern the destination pattern to match
187
+ * @return the {@link PathPatternMessageMatcher.Builder} for more configuration
188
+ */
189
+ public PathPatternMessageMatcher matcher (@ Nullable SimpMessageType type , String pattern ) {
190
+ Assert .notNull (pattern , "pattern must not be null" );
134
191
PathPattern pathPattern = this .parser .parse (pattern );
135
- PathPatternMessageMatcher matcher = new PathPatternMessageMatcher (pathPattern , this .parser );
136
- if (this .messageTypeMatcher != ANY_MESSAGE ) {
137
- matcher .setMessageTypeMatcher (this .messageTypeMatcher );
192
+ PathPatternMessageMatcher matcher = new PathPatternMessageMatcher (pathPattern ,
193
+ this .parser .getPathOptions ());
194
+ if (type != null ) {
195
+ matcher .setMessageTypeMatcher (new SimpMessageTypeMatcher (type ));
138
196
}
139
197
return matcher ;
140
198
}
141
199
142
- public PathPatternMessageMatcher matcher (String pattern , SimpMessageType type ) {
143
- Assert .notNull (type , "Type must not be null" );
144
- this .messageTypeMatcher = new SimpMessageTypeMatcher (type );
145
-
146
- return matcher (pattern );
147
- }
148
-
149
200
}
150
201
151
202
}
0 commit comments