[ARTEMIS-1890] Fix any-word wildcard matching in AddressImpl to match zero words

This commit is contained in:
Johan Stenberg 2018-05-26 20:12:26 +02:00 committed by Clebert Suconic
parent 545b82fbd7
commit 0ea84ef9ff
2 changed files with 106 additions and 56 deletions

View File

@ -24,10 +24,12 @@ import org.apache.activemq.artemis.core.config.WildcardConfiguration;
import org.apache.activemq.artemis.core.postoffice.Address; import org.apache.activemq.artemis.core.postoffice.Address;
/** /**
* splits an address string into its hierarchical parts split by '.' * Splits an address string into its hierarchical parts using {@link WildcardConfiguration#getDelimiter()} as delimiter.
*/ */
public class AddressImpl implements Address { public class AddressImpl implements Address {
private static final WildcardConfiguration DEFAULT_WILDCARD_CONFIGURATION = new WildcardConfiguration();
private final SimpleString address; private final SimpleString address;
private final SimpleString[] addressParts; private final SimpleString[] addressParts;
@ -39,10 +41,10 @@ public class AddressImpl implements Address {
private final WildcardConfiguration wildcardConfiguration; private final WildcardConfiguration wildcardConfiguration;
public AddressImpl(final SimpleString address) { public AddressImpl(final SimpleString address) {
this(address, new WildcardConfiguration()); this(address, DEFAULT_WILDCARD_CONFIGURATION);
} }
public AddressImpl(final SimpleString address, WildcardConfiguration wildcardConfiguration) { public AddressImpl(final SimpleString address, final WildcardConfiguration wildcardConfiguration) {
this.address = address; this.address = address;
this.wildcardConfiguration = wildcardConfiguration; this.wildcardConfiguration = wildcardConfiguration;
addressParts = address.split(wildcardConfiguration.getDelimiter()); addressParts = address.split(wildcardConfiguration.getDelimiter());
@ -81,76 +83,113 @@ public class AddressImpl implements Address {
linkedAddresses.remove(actualAddress); linkedAddresses.remove(actualAddress);
} }
/**
* This method should actually be called `isMatchedBy`.
*
* @return `true` if this equals otherAddr or this address is matched by a pattern represented by otherAddr
*/
@Override @Override
public boolean matches(final Address add) { public boolean matches(final Address otherAddr) {
if (containsWildCard == add.containsWildCard()) { if (otherAddr == null)
return address.equals(add.getAddress()); return false;
}
int pos = 0;
int matchPos = 0;
SimpleString nextToMatch; if (address.equals(otherAddr.getAddress()))
for (; matchPos < add.getAddressParts().length; ) { return true;
if (pos >= addressParts.length) {
// test for # as last address part final char sepAnyWords = wildcardConfiguration.getAnyWords();
return pos + 1 == add.getAddressParts().length && add.getAddressParts()[pos].equals(new SimpleString(wildcardConfiguration.getAnyWords())); final char sepSingleWord = wildcardConfiguration.getSingleWord();
final int thisAddrPartsLen = addressParts.length;
final int thisAddrPartsLastIdx = thisAddrPartsLen - 1;
final SimpleString[] otherAddrParts = otherAddr.getAddressParts();
final int otherAddrPartsLen = otherAddrParts.length;
final int otherAddrPartsLastIdx = otherAddrPartsLen - 1;
int thisIdx = 0;
int otherIdx = 0;
// iterate through all parts of otherAddr
while (otherIdx < otherAddrPartsLen) {
// check if we already tested the last part of this address
if (thisIdx > thisAddrPartsLastIdx) {
// check if last part of otherAddr is the any-words wildcard and report a match if so
if (otherIdx == otherAddrPartsLastIdx) {
final SimpleString otherAddrLastPart = otherAddrParts[otherAddrPartsLastIdx];
return otherAddrLastPart.length() > 0 && otherAddrLastPart.charAt(0) == sepAnyWords;
}
return false;
} }
SimpleString curr = addressParts[pos];
SimpleString next = addressParts.length > pos + 1 ? addressParts[pos + 1] : null; SimpleString thisCurr = addressParts[thisIdx];
SimpleString currMatch = add.getAddressParts()[matchPos]; final SimpleString otherCurr = otherAddrParts[otherIdx];
if (currMatch.equals(new SimpleString(wildcardConfiguration.getSingleWord()))) { final boolean otherCurrPartIsSingleChar = otherCurr.length() == 1;
pos++;
matchPos++; // handle single-word wildcard found in otherAddr
} else if (currMatch.equals(new SimpleString(wildcardConfiguration.getAnyWords()))) { if (otherCurrPartIsSingleChar && otherCurr.charAt(0) == sepSingleWord) {
if (matchPos == addressParts.length - 1) { thisIdx++;
pos++; otherIdx++;
matchPos++; continue;
} else if (next == null) { }
return false;
} else if (matchPos == add.getAddressParts().length - 1) { // handle any-words wildcard found in otherAddr
if (otherCurrPartIsSingleChar && otherCurr.charAt(0) == sepAnyWords) {
// if last part of otherAddr is any-words wildcard report a match
if (otherIdx == otherAddrPartsLastIdx)
return true; return true;
SimpleString thisNext;
// check if this address has more parts to check
if (thisIdx < thisAddrPartsLastIdx) {
thisNext = addressParts[thisIdx + 1];
} else { } else {
nextToMatch = add.getAddressParts()[matchPos + 1]; // no more parts to check, thus check the current part against the next part of otherAddr
while (curr != null) { thisNext = thisCurr;
if (curr.equals(nextToMatch)) {
break;
}
pos++;
curr = next;
next = addressParts.length > pos + 1 ? addressParts[pos + 1] : null;
}
if (curr == null) {
return false;
}
matchPos++;
} }
} else {
if (!curr.equals(currMatch)) { final SimpleString otherNext = otherAddrParts[otherIdx + 1];
// iterate through the remaining parts of this address until the part after the any-words wildcard of otherAddr is matched
while (thisCurr != null) {
if (thisCurr.equals(otherNext)) {
break;
}
thisIdx++;
thisCurr = thisNext;
thisNext = thisAddrPartsLastIdx > thisIdx ? addressParts[thisIdx + 1] : null;
}
// if no further part in this address matched the next part in otherAddr report a mismatch
if (thisCurr == null)
return false; return false;
} otherIdx++;
pos++; continue;
matchPos++;
} }
// compare current parts of bothaddresses and report mismatch if they differ
if (!thisCurr.equals(otherCurr))
return false;
thisIdx++;
otherIdx++;
} }
return pos == addressParts.length;
// report match if all parts of this address were checked
return thisIdx == thisAddrPartsLen;
} }
@Override @Override
public boolean equals(final Object o) { public boolean equals(final Object o) {
if (this == o) { if (this == o)
return true; return true;
}
if (o == null || getClass() != o.getClass()) { if (o == null || getClass() != o.getClass())
return false; return false;
}
AddressImpl address1 = (AddressImpl) o; if (address.equals(((AddressImpl) o).address))
return true;
if (!address.equals(address1.address)) { return false;
return false;
}
return true;
} }
@Override @Override

View File

@ -274,4 +274,15 @@ public class AddressImplTest extends ActiveMQTestBase {
Assert.assertFalse(a1.matches(w)); Assert.assertFalse(a1.matches(w));
} }
/**
* https://issues.apache.org/jira/browse/ARTEMIS-1890
*/
@Test
public void testV() {
final SimpleString s1 = new SimpleString("a.b.d");
final SimpleString s3 = new SimpleString("a.b.#.d");
final Address a1 = new AddressImpl(s1);
final Address w = new AddressImpl(s3);
Assert.assertTrue(a1.matches(w));
}
} }