QualifiedTag.java
package jasper.repository.spec;
import jasper.domain.Ref;
import jasper.domain.proj.HasOrigin;
import jasper.domain.proj.Tag;
import org.springframework.data.jpa.domain.Specification;
import java.util.List;
import java.util.stream.Collectors;
import static jasper.repository.spec.OriginSpec.isOrigin;
import static jasper.repository.spec.RefSpec.hasDownwardTag;
import static jasper.repository.spec.RefSpec.hasTag;
import static jasper.repository.spec.TagSpec.isDownwardTag;
import static jasper.repository.spec.TagSpec.isTag;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class QualifiedTag {
public static final String SELECTOR = "(?:\\*|" + Tag.REGEX + "|(?:" + Tag.REGEX + ")?(?:" + HasOrigin.REGEX_NOT_BLANK + "(?:[.][*])?|@\\*?))";
public final boolean not;
public final String tag;
public final String origin;
protected QualifiedTag(String qt) {
if (isBlank(qt)) {
not = false;
tag = "";
origin = "";
} else {
not = qt.startsWith("!");
if (not) qt = qt.substring(1);
var index = qt.indexOf("@");
if (index == -1) {
if (qt.equals("*")) {
tag = "";
origin = "";
} else {
tag = qt;
origin = "@*";
}
} else {
var rhs = qt.substring(index);
tag = qt.substring(0, index);
origin = rhs.equals("@") ? "" : rhs;
}
}
}
@Override
public String toString() {
return (not ? "!" : "") + tag
+ (origin.equals("@") ? ""
: origin.equals("@*") ? ""
: origin);
}
public boolean matches(String qt) {
return matches(selector(qt));
}
public boolean matches(QualifiedTag qt) {
return tag.equals(qt.tag) && origin.equals(qt.origin) && not == qt.not;
}
public boolean matchesDownwards(QualifiedTag qt) {
return Tag.matchesDownwards(tag, qt.tag) && origin.equals(qt.origin) && not == qt.not;
}
public boolean captures(String c) {
return captures(selector(c));
}
public boolean captures(QualifiedTag c) {
if (!tag.isEmpty() && !(tag.equals(c.tag) || c.tag.startsWith(tag + "/"))) return not;
if (!origin.endsWith("*") && !origin.equals(c.origin)) return not;
if (origin.endsWith(".*") && !c.origin.equals(origin.substring(0, origin.length() - 2)) && !c.origin.startsWith(origin.substring(0, origin.length() - 1))) return not;
return !not;
}
public boolean capturesDownwards(QualifiedTag c) {
if (!tag.isEmpty() && !Tag.capturesDownwards(tag, c.tag)) return not;
if (!origin.endsWith("*") && !origin.equals(c.origin)) return not;
if (origin.endsWith(".*") && !c.origin.equals(origin.substring(0, origin.length() - 2)) && !c.origin.startsWith(origin.substring(0, origin.length() - 1))) return not;
return !not;
}
public Specification<Ref> refSpec() {
var spec = Specification.<Ref>unrestricted();
if (isNotBlank(tag)) spec = spec.and(hasTag(tag));
spec = spec.and(isOrigin(origin));
return not ? Specification.not(spec) : spec;
}
public Specification<Ref> downwardRefSpec() {
var spec = Specification.<Ref>unrestricted();
if (isNotBlank(tag)) spec = spec.and(hasDownwardTag(tag));
spec = spec.and(isOrigin(origin));
return not ? Specification.not(spec) : spec;
}
public <T extends Tag> Specification<T> spec() {
var spec = Specification.<T>unrestricted();
if (isNotBlank(tag)) spec = spec.and(isTag(tag));
spec = spec.and(isOrigin(origin));
return not ? Specification.not(spec) : spec;
}
public <T extends Tag> Specification<T> downwardSpec() {
var spec = Specification.<T>unrestricted();
if (isNotBlank(tag)) spec = spec.and(isDownwardTag(tag));
spec = spec.and(isOrigin(origin));
return not ? Specification.not(spec) : spec;
}
/**
* Selector that represents an origin, but may be a wildcard or fixed tag.
* Missing origins will be set to the default origin.
*/
public static QualifiedTag tagOriginSelector(String qt) {
if (qt.startsWith("!")) throw new UnsupportedOperationException();
if (qt.startsWith("*")) throw new UnsupportedOperationException();
if (!qt.contains("@")) qt += "@"; // Missing origin implies default origin, not wildcard
return new QualifiedTag(qt);
}
/**
* Selector that represents a fixed tag and origin.
* Missing origins will be set to the default origin.
*/
public static QualifiedTag qt(String qt) {
if (qt.startsWith("!")) throw new UnsupportedOperationException();
if (qt.startsWith("@")) throw new UnsupportedOperationException();
if (qt.contains("*")) throw new UnsupportedOperationException();
if (!qt.contains("@")) qt += "@"; // Missing origin implies default origin, not wildcard
return new QualifiedTag(qt);
}
/**
* Selector that can include wildcards.
*/
public static QualifiedTag selector(String qt) {
if (qt.startsWith("!")) throw new UnsupportedOperationException();
return new QualifiedTag(qt);
}
/**
* Origin selector that can include wildcards.
*/
public static QualifiedTag originSelector(String qt) {
if (qt.isEmpty()) return selector("*");
return selector(qt);
}
public static String concat(String ...tags) {
var result = new StringBuilder();
for (var tag : tags) {
if (isEmpty(tag)) continue;
if (tag.startsWith("@")) tag = tag.substring(1);
if (!result.isEmpty()) {
result.append("/");
if (tag.startsWith("+") || tag.startsWith("_")) tag = tag.substring(1);
}
result.append(tag);
}
return result.toString();
}
/**
* Selector that represents a query atom. Can include wildcards or negations.
*/
public static QualifiedTag atom(String qt) {
return new QualifiedTag(qt);
}
public static List<QualifiedTag> qtList(String defaultOrigin, List<String> tags) {
var origin = isBlank(defaultOrigin) ? "@" : defaultOrigin;
return tags.stream()
.map(t -> t.contains("@") ? t : t + origin)
.map(QualifiedTag::qt)
.collect(Collectors.toList());
}
public static List<QualifiedTag> tagOriginList(List<String> tags) {
return tags.stream()
.map(QualifiedTag::tagOriginSelector)
.collect(Collectors.toList());
}
public static List<QualifiedTag> selectors(String defaultOrigin, List<String> tags) {
var origin = isBlank(defaultOrigin) ? "@" : defaultOrigin;
return tags.stream()
.map(t -> t.contains("@") ? t : t + origin)
.map(QualifiedTag::selector)
.collect(Collectors.toList());
}
}