in oak-core-spi/src/main/java/org/apache/jackrabbit/oak/namepath/JcrNameParser.java [79:192]
public static boolean parse(String jcrName, Listener listener, int index) {
// trivial check
int len = jcrName == null ? 0 : jcrName.length();
if (len == 0) {
listener.error("Empty name.");
return false;
}
if (".".equals(jcrName) || "..".equals(jcrName)) {
listener.error("Illegal name:" + jcrName);
return false;
}
// parse the name
String prefix;
int nameStart = 0;
int state = STATE_PREFIX_START;
for (int i = 0; i < len; i++) {
char c = jcrName.charAt(i);
if (c == ':') {
if (state == STATE_PREFIX_START) {
listener.error("Prefix must not be empty.");
return false;
} else if (state == STATE_PREFIX) {
prefix = jcrName.substring(0, i);
if (!XMLChar.isValidNCName(prefix)) {
listener.error("Invalid name prefix: "+ prefix);
return false;
}
state = STATE_NAME_START;
} else if (state == STATE_URI) {
// ignore -> validation of uri later on.
} else {
listener.error("'" + c + "' not allowed in name.");
return false;
}
} else if (c == '[' || c == ']' || c == '*' || c == '|') {
listener.error("'" + c + "' not allowed in name.");
return false;
} else if (c == '/') {
if (state == STATE_URI_START) {
state = STATE_URI;
} else if (state != STATE_URI) {
listener.error("'" + c + "' not allowed in name.");
return false;
}
} else if (c == '{') {
if (state == STATE_PREFIX_START) {
state = STATE_URI_START;
} else if (state == STATE_URI_START || state == STATE_URI) {
// second '{' in the uri-part -> no valid expanded jcr-name.
// therefore reset the nameStart and change state.
state = STATE_NAME;
nameStart = 0;
} else if (state == STATE_NAME_START) {
state = STATE_NAME;
nameStart = i;
}
} else if (c == '}') {
if (state == STATE_URI_START || state == STATE_URI) {
String tmp = jcrName.substring(1, i);
if (tmp.isEmpty() || tmp.indexOf(':') != -1) {
// The leading "{...}" part is empty or contains
// a colon, so we treat it as a valid namespace URI.
// More detailed validity checks (is it well formed,
// registered, etc.) are not needed here.
state = STATE_NAME_START;
} else if (tmp.equals("internal")) {
// As a special Jackrabbit backwards compatibility
// feature, support {internal} as a valid URI prefix
state = STATE_NAME_START;
} else if (tmp.indexOf('/') == -1) {
// The leading "{...}" contains neither a colon nor
// a slash, so we can interpret it as a a part of a
// normal local name.
state = STATE_NAME;
nameStart = 0;
} else {
listener.error("The URI prefix of the name " + jcrName + " is " +
"neither a valid URI nor a valid part of a local name.");
return false;
}
} else if (state == STATE_PREFIX_START) {
state = STATE_PREFIX; // prefix start -> validation later on will fail.
} else if (state == STATE_NAME_START) {
state = STATE_NAME;
nameStart = i;
}
} else {
if (state == STATE_PREFIX_START) {
state = STATE_PREFIX; // prefix start
} else if (state == STATE_NAME_START) {
state = STATE_NAME;
nameStart = i;
} else if (state == STATE_URI_START) {
state = STATE_URI;
}
}
}
// take care of qualified jcrNames starting with '{' that are not having
// a terminating '}' -> make sure there are no illegal characters present.
if (state == STATE_URI && (jcrName.indexOf(':') > -1 || jcrName.indexOf('/') > -1)) {
listener.error("Local name may not contain ':' nor '/'.");
return false;
}
if (nameStart == len || state == STATE_NAME_START) {
listener.error("Local name must not be empty.");
return false;
}
return listener.name(jcrName, index);
}