ARTEMIS-573 clarify filter documentation

This commit is contained in:
jbertram 2016-07-13 15:47:24 -05:00 committed by Andy Taylor
parent d7edf06689
commit 8a66d5f485
3 changed files with 107 additions and 0 deletions

View File

@ -49,3 +49,25 @@ refer to attributes of the core message in an expression:
Any other identifiers used in core filter expressions will be assumed to Any other identifiers used in core filter expressions will be assumed to
be properties of the message. be properties of the message.
The JMS spec states that a String property should not get converted to a
numeric when used in a selector. So for example, if a message has the `age`
property set to String `21` then the following selector should not match
it: `age > 18`. Since Apache ActiveMQ Artemis supports STOMP clients which
can only send messages with string properties, that restriction is a bit
limiting. Therefore, if you want your filter expressions to auto-convert String
properties the the appropriate number type, just prefix it with
`convert_string_expressions:`. If you changed the filter expression in the
previous example to be `convert_string_expressions:age > 18`, then it would
match the aforementioned message.
The JMS spec also states that property identifiers (and therefore the
identifiers which are valid for use in a filter expression) are an,
"unlimited-length sequence of letters and digits, the first of which must be
a letter. A letter is any character for which the method
`Character.isJavaLetter` returns `true`. This includes `_` and `$`. A letter
or digit is any character for which the method `Character.isJavaLetterOrDigit`
returns `true`." This constraint means that hyphens (i.e. `-`) cannot be used.
However, this constraint can be overcome by using the `hyphenated_props:`
prefix. For example, if a message had the `foo-bar` property set to `0` then
the filter expression `hyphenated_props:foo-bar = 0` would match it.

View File

@ -311,6 +311,13 @@ seconds.
> users can use heart-beats to maintain the life cycle of stomp > users can use heart-beats to maintain the life cycle of stomp
> connections. > connections.
### Selector/Filter expressions
Stomp subscribers can specify an expression used to select or filter
what the subscriber receives using the `selector` header. The filter
expression syntax follows the *core filter syntax* described in the
[Filter Expressions](filter-expressions.md) documentation.
### Stomp and JMS interoperability ### Stomp and JMS interoperability
#### Using JMS destinations #### Using JMS destinations

View File

@ -31,6 +31,12 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
import org.apache.activemq.artemis.api.core.client.ClientMessage;
import org.apache.activemq.artemis.api.core.client.ClientProducer;
import org.apache.activemq.artemis.api.core.client.ClientSession;
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
import org.apache.activemq.artemis.api.core.client.ServerLocator;
import org.apache.activemq.artemis.api.core.management.ResourceNames; import org.apache.activemq.artemis.api.core.management.ResourceNames;
import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient; import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
import org.apache.activemq.artemis.core.protocol.stomp.Stomp; import org.apache.activemq.artemis.core.protocol.stomp.Stomp;
@ -435,6 +441,35 @@ public class StompTest extends StompTestBase {
Assert.assertEquals("bar", "123", message.getStringProperty("bar")); Assert.assertEquals("bar", "123", message.getStringProperty("bar"));
} }
@Test
public void testSendMessageWithCustomHeadersAndHyphenatedSelector() throws Exception {
MessageConsumer consumer = session.createConsumer(queue, "hyphenated_props:b-ar = '123'");
String frame = "CONNECT\n" + "login: brianm\n" + "passcode: wombats\n\n" + Stomp.NULL;
sendFrame(frame);
frame = receiveFrame(10000);
Assert.assertTrue(frame.startsWith("CONNECTED"));
frame = "SEND\n" + "foo:abc\n" +
"b-ar:123\n" +
"destination:" +
getQueuePrefix() +
getQueueName() +
"\n\n" +
"Hello World" +
Stomp.NULL;
sendFrame(frame);
TextMessage message = (TextMessage) consumer.receive(1000);
Assert.assertNotNull(message);
Assert.assertEquals("Hello World", message.getText());
Assert.assertEquals("foo", "abc", message.getStringProperty("foo"));
Assert.assertEquals("b-ar", "123", message.getStringProperty("b-ar"));
}
@Test @Test
public void testSendMessageWithStandardHeaders() throws Exception { public void testSendMessageWithStandardHeaders() throws Exception {
@ -755,6 +790,49 @@ public class StompTest extends StompTestBase {
sendFrame(frame); sendFrame(frame);
} }
@Test
public void testSubscribeWithAutoAckAndHyphenatedSelector() throws Exception {
String frame = "CONNECT\n" + "login: brianm\n" + "passcode: wombats\n\n" + Stomp.NULL;
sendFrame(frame);
frame = receiveFrame(100000);
Assert.assertTrue(frame.startsWith("CONNECTED"));
frame = "SUBSCRIBE\n" + "destination:" +
getQueuePrefix() +
getQueueName() +
"\n" +
"selector: hyphenated_props:foo-bar = 'zzz'\n" +
"ack:auto\n\n" +
Stomp.NULL;
sendFrame(frame);
ServerLocator serverLocator = addServerLocator(ActiveMQClient.createServerLocator("vm://0"));
ClientSessionFactory clientSessionFactory = serverLocator.createSessionFactory();
ClientSession clientSession = clientSessionFactory.createSession(true, true);
ClientProducer producer = clientSession.createProducer(getQueuePrefix() + getQueueName());
ClientMessage ignoredMessage = clientSession.createMessage(false);
ignoredMessage.putStringProperty("foo-bar", "1234");
ignoredMessage.getBodyBuffer().writeNullableSimpleString(SimpleString.toSimpleString("Ignored message"));
ClientMessage realMessage = clientSession.createMessage(false);
realMessage.putStringProperty("foo-bar", "zzz");
realMessage.getBodyBuffer().writeNullableSimpleString(SimpleString.toSimpleString("Real message"));
producer.send(ignoredMessage);
producer.send(realMessage);
frame = receiveFrame(10000);
Assert.assertTrue(frame.startsWith("MESSAGE"));
Assert.assertTrue("Should have received the real message but got: " + frame, frame.indexOf("Real message") > 0);
frame = "DISCONNECT\n" + "\n\n" + Stomp.NULL;
sendFrame(frame);
}
@Test @Test
public void testSubscribeWithClientAck() throws Exception { public void testSubscribeWithClientAck() throws Exception {