Skip to content

Commit fc6fc14

Browse files
committed
Extract PathMatcher and add tests
1 parent a2570f5 commit fc6fc14

File tree

12 files changed

+141
-80
lines changed

12 files changed

+141
-80
lines changed

example-client/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ buildscript {
77
google()
88
}
99
dependencies {
10-
classpath 'com.android.tools.build:gradle:3.2.1'
10+
classpath 'com.android.tools.build:gradle:3.3.0'
1111
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
1212
}
1313
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
#Tue Sep 05 08:26:08 MST 2017
1+
#Sun Jan 20 23:59:55 EET 2019
22
distributionBase=GRADLE_USER_HOME
33
distributionPath=wrapper/dists
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
6+
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip

lib/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ buildscript {
77
google()
88
}
99
dependencies {
10-
classpath 'com.android.tools.build:gradle:3.2.1'
10+
classpath 'com.android.tools.build:gradle:3.3.0'
1111
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
1212
classpath 'org.codehaus.groovy:groovy-android-gradle-plugin:2.0.0'
1313
}
@@ -59,7 +59,7 @@ dependencies {
5959
api 'com.squareup.okhttp3:okhttp:3.12.1'
6060
implementation 'com.android.support:support-annotations:28.0.0'
6161
testImplementation 'com.andrewreitz:spock-android:2.0.0'
62-
testImplementation 'org.testcontainers:testcontainers:1.8.0'
62+
testImplementation 'org.testcontainers:testcontainers:1.10.5'
6363
testImplementation 'org.spockframework:spock-core:1.1-groovy-2.4'
6464
testImplementation 'org.java-websocket:Java-WebSocket:1.3.6'
6565
testImplementation 'com.squareup.okhttp3:okhttp:3.12.1'

lib/src/main/java/ua/naiksoftware/stomp/StompClient.java

Lines changed: 18 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import io.reactivex.subjects.PublishSubject;
2020
import ua.naiksoftware.stomp.dto.StompCommand;
2121
import ua.naiksoftware.stomp.dto.StompMessage;
22+
import ua.naiksoftware.stomp.pathmatcher.PathMatcher;
23+
import ua.naiksoftware.stomp.pathmatcher.SimplePathMatcher;
2224
import ua.naiksoftware.stomp.provider.ConnectionProvider;
2325
import ua.naiksoftware.stomp.dto.LifecycleEvent;
2426
import ua.naiksoftware.stomp.dto.StompHeader;
@@ -43,7 +45,7 @@ public class StompClient {
4345
private PublishSubject<StompMessage> mMessageStream;
4446
private ConcurrentHashMap<String, Flowable<StompMessage>> mStreamMap;
4547
private final BehaviorSubject<Boolean> mConnectionStream;
46-
private Parser parser;
48+
private PathMatcher pathMatcher;
4749
private Disposable mLifecycleDisposable;
4850
private Disposable mMessagesDisposable;
4951
private List<StompHeader> mHeaders;
@@ -56,27 +58,7 @@ public StompClient(ConnectionProvider connectionProvider) {
5658
mMessageStream = PublishSubject.create();
5759
mStreamMap = new ConcurrentHashMap<>();
5860
mConnectionStream = BehaviorSubject.createDefault(false);
59-
parser = Parser.NONE;
60-
}
61-
62-
public enum Parser {
63-
NONE,
64-
RABBITMQ
65-
}
66-
67-
/**
68-
* Set the wildcard parser for Topic subscription.
69-
* <p>
70-
* Right now, the only options are NONE and RABBITMQ.
71-
* <p>
72-
* When set to RABBITMQ, topic subscription allows for RMQ-style wildcards.
73-
* <p>
74-
* See more info <a href="https://www.rabbitmq.com/tutorials/tutorial-five-java.html">here</a>.
75-
*
76-
* @param parser Set to NONE by default
77-
*/
78-
public void setParser(Parser parser) {
79-
this.parser = parser;
61+
pathMatcher = new SimplePathMatcher();
8062
}
8163

8264
/**
@@ -243,7 +225,7 @@ public Flowable<StompMessage> topic(@NonNull String destPath, List<StompHeader>
243225
else if (!mStreamMap.containsKey(destPath))
244226
mStreamMap.put(destPath,
245227
mMessageStream
246-
.filter(msg -> matches(destPath, msg))
228+
.filter(msg -> pathMatcher.matches(destPath, msg))
247229
.toFlowable(BackpressureStrategy.BUFFER)
248230
.doOnSubscribe(disposable -> subscribePath(destPath, headerList).subscribe())
249231
.doFinally(() -> unsubscribePath(destPath).subscribe())
@@ -267,56 +249,19 @@ public void setLegacyWhitespace(boolean legacyWhitespace) {
267249
this.legacyWhitespace = legacyWhitespace;
268250
}
269251

270-
private boolean matches(String path, StompMessage msg) {
271-
String dest = msg.findHeader(StompHeader.DESTINATION);
272-
if (dest == null) return false;
273-
boolean ret;
274-
275-
switch (parser) {
276-
case NONE:
277-
ret = path.equals(dest);
278-
break;
279-
280-
case RABBITMQ:
281-
// for example string "lorem.ipsum.*.sit":
282-
283-
// split it up into ["lorem", "ipsum", "*", "sit"]
284-
String[] split = path.split("\\.");
285-
ArrayList<String> transformed = new ArrayList<>();
286-
// check for wildcards and replace with corresponding regex
287-
for (String s : split) {
288-
switch (s) {
289-
case "*":
290-
transformed.add("[^.]+");
291-
break;
292-
case "#":
293-
// TODO: make this work with zero-word
294-
// e.g. "lorem.#.dolor" should ideally match "lorem.dolor"
295-
transformed.add(".*");
296-
break;
297-
default:
298-
transformed.add(s);
299-
break;
300-
}
301-
}
302-
// at this point, 'transformed' looks like ["lorem", "ipsum", "[^.]+", "sit"]
303-
StringBuilder sb = new StringBuilder();
304-
for (String s : transformed) {
305-
if (sb.length() > 0) sb.append("\\.");
306-
sb.append(s);
307-
}
308-
String join = sb.toString();
309-
// join = "lorem\.ipsum\.[^.]+\.sit"
310-
311-
ret = dest.matches(join);
312-
break;
313-
314-
default:
315-
ret = false;
316-
break;
317-
}
318-
319-
return ret;
252+
/**
253+
* Set the wildcard or other matcher for Topic subscription.
254+
* <p>
255+
* Right now, the only options are simple, rmq supported.
256+
* But you can write you own matcher by implementing {@link PathMatcher}
257+
* <p>
258+
* When set to {@link ua.naiksoftware.stomp.pathmatcher.RabbitPathMatcher}, topic subscription allows for RMQ-style wildcards.
259+
* <p>
260+
*
261+
* @param pathMatcher Set to {@link SimplePathMatcher} by default
262+
*/
263+
public void setPathMatcher(PathMatcher pathMatcher) {
264+
this.pathMatcher = pathMatcher;
320265
}
321266

322267
private Completable subscribePath(String destinationPath, @Nullable List<StompHeader> headerList) {

lib/src/main/java/ua/naiksoftware/stomp/dto/StompHeader.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,9 @@ public String getKey() {
2828
public String getValue() {
2929
return mValue;
3030
}
31+
32+
@Override
33+
public String toString() {
34+
return "StompHeader{" + mKey + '=' + mValue + '}';
35+
}
3136
}

lib/src/main/java/ua/naiksoftware/stomp/dto/StompMessage.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,13 @@ public static StompMessage from(@Nullable String data) {
9393

9494
return new StompMessage(command, headers, payload);
9595
}
96+
97+
@Override
98+
public String toString() {
99+
return "StompMessage{" +
100+
"command='" + mStompCommand + '\'' +
101+
", headers=" + mStompHeaders +
102+
", payload='" + mPayload + '\'' +
103+
'}';
104+
}
96105
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package ua.naiksoftware.stomp.pathmatcher;
2+
3+
import ua.naiksoftware.stomp.dto.StompMessage;
4+
5+
public interface PathMatcher {
6+
7+
boolean matches(String path, StompMessage msg);
8+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package ua.naiksoftware.stomp.pathmatcher;
2+
3+
import ua.naiksoftware.stomp.dto.StompHeader;
4+
import ua.naiksoftware.stomp.dto.StompMessage;
5+
6+
import java.util.ArrayList;
7+
8+
public class RabbitPathMatcher implements PathMatcher {
9+
10+
/**
11+
* RMQ-style wildcards.
12+
* See more info <a href="https://www.rabbitmq.com/tutorials/tutorial-five-java.html">here</a>.
13+
*/
14+
@Override
15+
public boolean matches(String path, StompMessage msg) {
16+
String dest = msg.findHeader(StompHeader.DESTINATION);
17+
if (dest == null) return false;
18+
19+
// for example string "lorem.ipsum.*.sit":
20+
21+
// split it up into ["lorem", "ipsum", "*", "sit"]
22+
String[] split = path.split("\\.");
23+
ArrayList<String> transformed = new ArrayList<>();
24+
// check for wildcards and replace with corresponding regex
25+
for (String s : split) {
26+
switch (s) {
27+
case "*":
28+
transformed.add("[^.]+");
29+
break;
30+
case "#":
31+
// TODO: make this work with zero-word
32+
// e.g. "lorem.#.dolor" should ideally match "lorem.dolor"
33+
transformed.add(".*");
34+
break;
35+
default:
36+
transformed.add(s.replaceAll("\\*", ".*"));
37+
break;
38+
}
39+
}
40+
// at this point, 'transformed' looks like ["lorem", "ipsum", "[^.]+", "sit"]
41+
StringBuilder sb = new StringBuilder();
42+
for (String s : transformed) {
43+
if (sb.length() > 0) sb.append("\\.");
44+
sb.append(s);
45+
}
46+
String join = sb.toString();
47+
// join = "lorem\.ipsum\.[^.]+\.sit"
48+
49+
return dest.matches(join);
50+
}
51+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package ua.naiksoftware.stomp.pathmatcher;
2+
3+
import ua.naiksoftware.stomp.dto.StompHeader;
4+
import ua.naiksoftware.stomp.dto.StompMessage;
5+
6+
public class SimplePathMatcher implements PathMatcher {
7+
8+
@Override
9+
public boolean matches(String path, StompMessage msg) {
10+
String dest = msg.findHeader(StompHeader.DESTINATION);
11+
if (dest == null) return false;
12+
else return path.equals(dest);
13+
}
14+
}

lib/src/test/groovy/ua/naiksoftware/stomp/Configuration.groovy

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import groovy.util.logging.Slf4j
55
import org.testcontainers.containers.BindMode
66
import org.testcontainers.containers.GenericContainer
77
import org.testcontainers.containers.output.OutputFrame
8+
import org.testcontainers.containers.startupcheck.StartupCheckStrategy
89
import org.testcontainers.containers.wait.strategy.Wait
910
import spock.lang.Shared
1011
import spock.lang.Specification
@@ -30,7 +31,7 @@ class Configuration extends AndroidSpecification {
3031
.withCommand('java -jar /app.jar')
3132
.withLogConsumer({ frame -> println frame.utf8String })
3233
// .waitingFor(Wait.forHttp('/health'))
33-
.withExposedPorts(80)
34+
.withExposedPorts(8080)
3435
testServer.start()
3536
return testServer
3637
}

0 commit comments

Comments
 (0)