WildcardEntry.java
package emissary.directory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
/**
* Handle the details of a wildcard directory entry including iterating through the possible directory match strings A
* dataId will be wildcarded like this, based on dash and paren markings in the dataType.
* <ul>
* <li>FOO-BAR(ASCII-TRANSLIT)-BAZ(SHAZAM)-BAM_MESSAGE</li>
* <li>FOO-BAR(ASCII-TRANSLIT)-BAZ(*)-BAM_MESSAGE</li>
* <li>FOO-BAR(*)-BAZ(*)-BAM_MESSAGE</li>
* <li>FOO-BAR(*)-BAZ(*)-*</li>
* <li>FOO-BAR(*)-*</li>
* <li>FOO-*</li>
* <li></li>
* </ul>
*
* <ol>
* <li>The complete unchanged entry is returned first, so an exact match will work like it always has worked
* before.</li>
* <li>Next the parenthetical expressions are wildcarded out starting from the right and moving left until all have been
* changed to wildcards. Each step wildcards another parenthetical expression without reverting the previous one. So you
* currently cannot get a wildcard match on the non-rightmost expression without every one to the right of it also being
* wildcarded.</li>
* <li>Finally, each dash delimited expression is wildcarded, then eliminated starting from the right until there is
* nothing left but the pure wildcard entry "*". The wildcarded parenthetical expressions are left wildcarded
* for this stage, so as things are dropped off, you can only match wildcarded parentheticals that are still remaining
* to the left.</li>
* </ol>
*/
public class WildcardEntry {
private static final Logger logger = LoggerFactory.getLogger(WildcardEntry.class);
String dataType;
@Nullable
String serviceType;
@Nullable
List<String> wc = null;
private static final char DASH = '-';
private static final char OPEN = '(';
private static final char CLOS = ')';
private static final String KSEP = KeyManipulator.DATAIDSEPARATOR;
private static final int KSPL = KSEP.length();
private static final String DASH_WC = "-*"; // DASH Wildcard
private static final String PAREN_WC = "(*)"; // PAREN Wildcard
private static final String PURE_WC = "*"; // PURE Wildcard
public WildcardEntry(final String s) {
parseEntry(s);
}
/**
* Parse the entry into the ordered list of wildcard entries
*/
private synchronized void parseEntry(final String entry) {
final int pos = entry.indexOf(KSEP);
if (pos > 0) {
this.dataType = entry.substring(0, pos);
this.serviceType = entry.substring(pos + KSPL);
} else {
this.dataType = entry;
this.serviceType = null;
}
}
/**
* Iterator over the wildcard entries in order
*/
public Iterator<String> iterator() {
load();
return this.wc.iterator();
}
/**
* Get the results of parsing as a set
*/
public Set<String> asSet() {
load();
return new HashSet<>(this.wc);
}
/**
* Lazy load of the list containing wildcarded parts
*/
private synchronized void load() {
if (this.wc == null) {
this.wc = new ArrayList<>();
// Put the original on the list first
if (this.serviceType != null) {
this.wc.add(this.dataType + KSEP + this.serviceType);
} else {
this.wc.add(this.dataType);
}
// Replace paren parts one at a time from the right
String dt = this.dataType;
int lastOpen = this.dataType.length();
boolean done = false;
while (!done) {
for (int i = lastOpen - 1; i >= 0; i--) {
if (dt.charAt(i) == OPEN) {
final int clos = dt.indexOf(CLOS, i);
if (clos > i) {
dt = dt.substring(0, i) + PAREN_WC + dt.substring(clos + 1);
if (this.serviceType != null) {
this.wc.add(dt + KSEP + this.serviceType);
} else {
this.wc.add(dt);
}
lastOpen = i;
break;
}
done = true;
break;
}
if (i == 0) {
done = true;
}
}
}
// Now working with the totally replaced paren string
// handle the dashed parts
for (int i = dt.length() - 1; i >= 0; i--) {
if (dt.charAt(i) == DASH) {
if (this.serviceType != null) {
this.wc.add(dt.substring(0, i) + DASH_WC + KSEP + this.serviceType);
} else {
this.wc.add(dt.substring(0, i) + DASH_WC);
}
}
}
if (this.serviceType != null) {
this.wc.add(PURE_WC + KSEP + this.serviceType);
} else {
this.wc.add(PURE_WC);
}
}
}
/**
* Select an entry from the map
*
* @param dataId the string to wildcard
* @param map the map to choose from
* @return the found entry
*/
public static DirectoryEntryList getWildcardedEntry(final String dataId, final DirectoryEntryMap map) {
final DirectoryEntryList matches = new DirectoryEntryList();
final WildcardEntry we = new WildcardEntry(dataId);
logger.debug("Got a set of size {} from {}", we.size(), dataId);
for (final String w : we.asSet()) {
final DirectoryEntryList found = map.get(w);
if (found != null) {
logger.debug("Found a wildcard match on {} size={}", w, found.size());
matches.addAll(found);
} else {
logger.debug("SKipping {} nothing in map", w);
}
}
return matches;
}
/**
* Size of this wildcard entry set
*/
public int size() {
load();
return this.wc.size();
}
}