cdc.util.rdb.RdbElementPath Maven / Gradle / Ivy
package cdc.util.rdb;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import cdc.util.lang.Checks;
/**
* Path associated to an element.
*
* For elements that can have siblings with same name (e.g., data type, function or procedure),
* a Path, as currently defined, can be ambiguous.
*
* @author Damien Carbonne
*
*/
public final class RdbElementPath implements Comparable {
private final Part[] parts;
public static final char KIND_SEPARATOR = ':';
public static final char PART_SEPARATOR = '/';
public static final class Part {
private final RdbElementKind kind;
private final String name;
Part(RdbElementKind kind,
String name) {
this.kind = kind;
this.name = name;
}
Part(RdbElement element) {
this.kind = element.getKind();
this.name = element.getName();
}
public RdbElementKind getKind() {
return kind;
}
public String getName() {
return name;
}
@Override
public int hashCode() {
return kind.hashCode() + 31 * name.hashCode();
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!(object instanceof Part)) {
return false;
}
final Part other = (Part) object;
return kind == other.kind && name.equals(other.name);
}
@Override
public String toString() {
return "[" + kind + ":" + name + "]";
}
}
RdbElementPath(RdbElement element) {
this.parts = new Part[element.getDepth()];
int index = parts.length;
RdbElement iter = element;
while (iter != null) {
index--;
this.parts[index] = new Part(iter);
iter = iter.getParent();
}
}
private RdbElementPath(RdbElementPath path,
int length) {
this.parts = new Part[length];
for (int index = 0; index < length; index++) {
this.parts[index] = path.parts[index];
}
}
public RdbElementPath(RdbElementKind kind,
String s) {
Checks.isNotNull(kind, "kind");
Checks.isNotNull(s, "s");
// Extract names
final List names = new ArrayList<>();
int from = 0;
// Number of part separators
int seps = 0;
while (from < s.length()) {
final int to = s.indexOf(PART_SEPARATOR, from);
if (to < 0) {
names.add(s.substring(from));
from = s.length();
} else {
names.add(s.substring(from, to));
from = to + 1;
seps++;
}
}
if (seps == names.size()) {
names.add("");
}
// Build parts
if (kind.getDepth() == names.size()) {
this.parts = new Part[names.size()];
RdbElementKind k = kind;
for (int index = parts.length - 1; index >= 0; index--) {
final Part part = new Part(k, names.get(index));
this.parts[index] = part;
k = k.getParent();
}
} else {
throw new IllegalArgumentException("Invalid number of parts " + names.size()
+ " for " + kind
+ ", expecting " + kind.getDepth() + " in '" + s + "'");
}
}
public RdbElementPath(String s) {
this(getKind(s),
getPath(s));
}
private static RdbElementKind getKind(String s) {
Checks.isNotNull(s, "s");
final int pos = s.indexOf(KIND_SEPARATOR);
if (pos < 0) {
throw new IllegalArgumentException("Invalid path '" + s + "', missing '" + KIND_SEPARATOR + "'");
}
try {
return RdbElementKind.valueOf(s.substring(0, pos));
} catch (final IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid path '" + s + "', can not decode '" + s.substring(0, pos) + "'");
}
}
private static String getPath(String s) {
Checks.isNotNull(s, "s");
final int pos = s.indexOf(KIND_SEPARATOR);
if (pos < 0) {
throw new IllegalArgumentException("Invalid path '" + s + "', missing '" + KIND_SEPARATOR + "'");
} else {
return s.substring(pos + 1);
}
}
public int getLength() {
return parts.length;
}
public Part[] getParts() {
return parts;
}
public Part getPart(int index) {
return parts[index];
}
public RdbElementKind getKind() {
return parts[parts.length - 1].getKind();
}
public boolean hasPart(RdbElementKind kind) {
Checks.isNotNull(kind, "kind");
final int index = kind.getDepth() - 1;
return index < parts.length && parts[index].getKind() == kind;
}
public Part getPart(RdbElementKind kind) {
Checks.isNotNull(kind, "kind");
final int index = kind.getDepth() - 1;
final Part part = index < parts.length ? parts[index] : null;
return part != null && part.getKind() == kind ? part : null;
}
public RdbElementPath getParent() {
if (getLength() == 1) {
return null;
} else {
return new RdbElementPath(this, getLength() - 1);
}
}
@Override
public int hashCode() {
return Arrays.hashCode(parts);
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!(object instanceof RdbElementPath)) {
return false;
}
final RdbElementPath other = (RdbElementPath) object;
return Arrays.equals(parts, other.parts);
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append(getKind().name());
builder.append(KIND_SEPARATOR);
for (int index = 0; index < getLength(); index++) {
if (index > 0) {
builder.append(PART_SEPARATOR);
}
builder.append(getPart(index).getName());
}
return builder.toString();
}
@Override
public int compareTo(RdbElementPath other) {
return toString().compareTo(other.toString());
}
}