gemmellr commented on code in PR #4710:
URL: https://github.com/apache/activemq-artemis/pull/4710#discussion_r1452215672


##########
artemis-server/src/test/java/org/apache/activemq/artemis/core/config/WildcardConfigurationTest.java:
##########
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.core.config;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class WildcardConfigurationTest extends Assert {

Review Comment:
   I'd expect to see more general unit testing of the new methods, e.g the new 
bits around equality and returning the input directly when calling for 
conversion if they are the exact same or equal WildcardConfiguration. Every one 
of the calls in the added test uses different/non-equal WildcardConfiguration 
objects and also mutates something in the input string.



##########
docs/user-manual/versions.adoc:
##########
@@ -31,6 +31,13 @@ These settings are now no longer required.
 +
 Configure `defaultMqttSessionExpiryInterval` instead.
 
+* Due to https://issues.apache.org/jira/browse/ARTEMIS-4532[ARTEMIS-4532] the 
names of addresses and queues related to MQTT topics and subscriptions 
respectively may change. This will only impact you:
++
+  . If the broker is configured to use a xref:wildcard-syntax.adoc[wildcard 
syntax] which doesn't match the xref:mqtt.adoc#wildcard-syntax[MQTT wildcard 
syntax].
+  . If you are using characters from the broker's wildcard syntax in your MQTT 
topic names or topic filters.

Review Comment:
   It could be clearer from the text both items in the list need apply, just to 
drive it home



##########
tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt5/spec/controlpackets/PublishTests.java:
##########
@@ -311,15 +312,15 @@ public void testRetainFlagFalse() throws Exception {
 
       // send retained message
       producer.publish(TOPIC, RETAINED_PAYLOAD.getBytes(), 2, true);
-      Wait.assertTrue(() -> 
server.locateQueue(MQTTUtil.convertMqttTopicFilterToCore(MQTTUtil.MQTT_RETAIN_ADDRESS_PREFIX,
 TOPIC, MQTTUtil.MQTT_WILDCARD)).getMessageCount() == 1, 1000, 100);
+      Wait.assertTrue(() -> getRetainedMessageQueue(TOPIC).getMessageCount() 
== 1, 1000, 100);
 
       // send an unretained message; should *not* remove the existing retained 
message
       producer.publish(TOPIC, UNRETAINED_PAYLOAD.getBytes(), 2, false);
 
       producer.disconnect();
       producer.close();
 
-      Wait.assertFalse(() -> 
server.locateQueue(MQTTUtil.convertMqttTopicFilterToCore(MQTTUtil.MQTT_RETAIN_ADDRESS_PREFIX,
 TOPIC, MQTTUtil.MQTT_WILDCARD)).getMessageCount() > 1, 1000, 100);
+      Wait.assertFalse(() -> getRetainedMessageQueue(TOPIC).getMessageCount() 
> 1, 1000, 100);

Review Comment:
   Is there a reason why the assert should not just be checking for a count of 
2 ?



##########
tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt5/spec/controlpackets/PublishTests.java:
##########
@@ -269,15 +270,15 @@ public void testRetainFlagWithEmptyMessage() throws 
Exception {
       // send first retained message
       producer.publish(TOPIC, "retain1".getBytes(), 2, true);
 
-      Wait.assertTrue(() -> 
server.locateQueue(MQTTUtil.convertMqttTopicFilterToCore(MQTTUtil.MQTT_RETAIN_ADDRESS_PREFIX,
 TOPIC, MQTTUtil.MQTT_WILDCARD)).getMessageCount() == 1, 2000, 100);
+      Wait.assertTrue(() -> getRetainedMessageQueue(TOPIC).getMessageCount() 
== 1, 2000, 100);

Review Comment:
   Lots of tests asserting the queue count is 1 now, but would be better if 
they also verified it was 0 to begin with.



##########
artemis-server/src/main/java/org/apache/activemq/artemis/core/config/WildcardConfiguration.java:
##########
@@ -119,19 +138,94 @@ public String getSingleWordString() {
       return singleWordString;
    }
 
-   public void setSingleWord(char singleWord) {
+   public WildcardConfiguration setSingleWord(char singleWord) {
       this.singleWord = singleWord;
       this.singleWordString = String.valueOf(singleWord);
+      return this;
    }
 
-   public String convert(String filter, WildcardConfiguration to) {
-      if (this.equals(to)) {
-         return filter;
+   /**
+    * Convert the input from this WildcardConfiguration into the specified 
WildcardConfiguration.
+    *
+    * If the input already contains characters defined in the target 
WildcardConfiguration then those characters will
+    * be escaped and preserved as such in the returned String. That said, 
wildcard characters which are the same
+    * between the two configurations will not be escaped
+    *
+    * If the input already contains escaped characters defined in this 
WildcardConfiguration then those characters will
+    * be unescaped after conversion and restored in the returned String.
+    *
+    * @param input  the String to convert
+    * @param target the WildcardConfiguration to convert the input into
+    * @return the converted String
+    */
+   public String convert(final String input, final WildcardConfiguration 
target) {
+      if (this.equals(target)) {
+         return input;
       } else {
-         return filter
-            .replace(getDelimiter(), to.getDelimiter())
-            .replace(getSingleWord(), to.getSingleWord())
-            .replace(getAnyWords(), to.getAnyWords());
+         boolean escaped = isEscaped(input);
+         StringBuilder result;
+         if (!escaped) {
+            result = new StringBuilder(target.escape(input, this));
+         } else {
+            result = new StringBuilder(input);
+         }
+         replaceChar(result, getDelimiter(), target.getDelimiter());
+         replaceChar(result, getSingleWord(), target.getSingleWord());
+         replaceChar(result, getAnyWords(), target.getAnyWords());
+         if (escaped) {
+            return unescape(result.toString());
+         } else {
+            return result.toString();
+         }
+      }
+   }
+
+   private String escape(final String input, WildcardConfiguration from) {
+      String result = input.replace(escapeString, escapeString + escapeString);
+      if (delimiter != from.getDelimiter()) {
+         result = result.replace(getDelimiterString(), escapeString + 
getDelimiterString());
+      }
+      if (singleWord != from.getSingleWord()) {
+         result = result.replace(getSingleWordString(), escapeString + 
getSingleWordString());
+      }
+      if (anyWords != from.getAnyWords()) {
+         result = result.replace(getAnyWordsString(), escapeString + 
getAnyWordsString());
+      }
+      return result;
+   }
+
+   private String unescape(final String input) {
+      return input
+         .replace(escapeString + escapeString, escapeString)
+         .replace(ESCAPE + getDelimiterString(), getDelimiterString())
+         .replace(ESCAPE + getSingleWordString(), getSingleWordString())
+         .replace(ESCAPE + getAnyWordsString(), getAnyWordsString());
+   }
+
+   private boolean isEscaped(final String input) {
+      for (int i = 0; i < input.length() - 1; i++) {
+         if (input.charAt(i) == ESCAPE && (input.charAt(i + 1) == 
getDelimiter() || input.charAt(i + 1) == getSingleWord() || input.charAt(i + 1) 
== getAnyWords())) {
+            return true;
+         }
+      }

Review Comment:
   To be sure, this would throw IOOBE if the final character is the escape 
since it assumes there is another character, is that ok (doesnt seem like it 
should really come up often)?



##########
docs/user-manual/versions.adoc:
##########
@@ -31,6 +31,13 @@ These settings are now no longer required.
 +
 Configure `defaultMqttSessionExpiryInterval` instead.
 
+* Due to https://issues.apache.org/jira/browse/ARTEMIS-4532[ARTEMIS-4532] the 
names of addresses and queues related to MQTT topics and subscriptions 
respectively may change. This will only impact you:
++
+  . If the broker is configured to use a xref:wildcard-syntax.adoc[wildcard 
syntax] which doesn't match the xref:mqtt.adoc#wildcard-syntax[MQTT wildcard 
syntax].
+  . If you are using characters from the broker's wildcard syntax in your MQTT 
topic names or topic filters.
++
+In this case the characters from the broker's wildcard syntax that do not 
match the characters in the MQTT wildcard syntax will be escaped with a 
backslash (i.e. `\`).

Review Comment:
   Suggestion for what a user might need to do to adapt? E.g rename an existing 
queues to what they 'should be' now?



##########
tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt5/spec/controlpackets/PublishTests.java:
##########
@@ -653,6 +654,10 @@ public void messageArrived(String topic, MqttMessage 
message) throws Exception {
       consumer.close();
    }
 
+   private Queue getRetainedMessageQueue(String TOPIC) {
+      return 
server.locateQueue(MQTTUtil.convertMqttTopicFilterToCore(MQTTUtil.MQTT_RETAIN_ADDRESS_PREFIX,
 TOPIC, server.getConfiguration().getWildcardConfiguration()));
+   }

Review Comment:
   Both here and elsewhere, there appear to be so many tests using the 
_MQTTUtil.convertMqttTopicFilterToCore_ method to calculate  queue names, as 
does the _MQTTSubscriptionManager.getQueueNameForTopic_ method which appears to 
be the location targeted most by the change in this PR. That seems to leave 
most of these tests open to compensating bugs in whatever that method happens 
to return. It does seem to be changed fairly regularly. I think it would be 
good to see some direct unit testing of what this queue naming method does to 
confirm it is actually meeting expectations.
   
   Also, perhaps convert the TOPIC parameter name here to lowercase? Its a 
little odd to use TOPIC for it, and potentially confusing when that name is 
already widely used elsewhere in the class.



##########
artemis-server/src/test/java/org/apache/activemq/artemis/core/config/WildcardConfigurationTest.java:
##########
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.core.config;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class WildcardConfigurationTest extends Assert {
+
+   public static final WildcardConfiguration MQTT_WILDCARD = new 
WildcardConfiguration().setDelimiter('/').setAnyWords('#').setSingleWord('+');
+   public static final WildcardConfiguration DEFAULT_WILDCARD = new 
WildcardConfiguration();

Review Comment:
   Can these be private?
   
   Worth an assert that the default configuration object is as expected?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to