in vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/PackageId.java [470:590]
private static void assertValidJcrName(String jcrName) throws IllegalArgumentException {
// trivial check
int len = jcrName == null ? 0 : jcrName.length();
if (len == 0) {
throw new IllegalArgumentException("empty name");
}
if (".".equals(jcrName) || "..".equals(jcrName)) {
throw new IllegalArgumentException(jcrName);
}
// parse the name
String prefix;
int nameStart = 0;
int state = STATE_PREFIX_START;
boolean trailingSpaces = false;
for (int i = 0; i < len; i++) {
char c = jcrName.charAt(i);
if (c == ':') {
if (state == STATE_PREFIX_START) {
throw new IllegalArgumentException("Prefix must not be empty");
} else if (state == STATE_PREFIX) {
if (trailingSpaces) {
throw new IllegalArgumentException("Trailing spaces not allowed");
}
prefix = jcrName.substring(0, i);
if (!XMLChar.isValidNCName(prefix)) {
throw new IllegalArgumentException("Invalid name prefix: "+ prefix);
}
state = STATE_NAME_START;
} else if (state == STATE_URI) {
// ignore -> validation of uri later on.
} else {
throw new IllegalArgumentException("'" + c + "' not allowed in name");
}
trailingSpaces = false;
} else if (c == ' ') {
if (state == STATE_PREFIX_START || state == STATE_NAME_START) {
throw new IllegalArgumentException("'" + c + "' not valid name start");
}
trailingSpaces = true;
} else if (Character.isWhitespace(c) || c == '[' || c == ']' || c == '*' || c == '|') {
throw new IllegalArgumentException("'" + c + "' not allowed in name");
} else if (c == '/') {
if (state == STATE_URI_START) {
state = STATE_URI;
} else if (state != STATE_URI) {
throw new IllegalArgumentException("'" + c + "' not allowed in name");
}
trailingSpaces = 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;
}
trailingSpaces = false;
} else if (c == '}') {
if (state == STATE_URI_START || state == STATE_URI) {
String tmp = jcrName.substring(1, i);
if (tmp.length() == 0 || 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 ("internal".equals(tmp)) {
// 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 {
throw new IllegalArgumentException(
"The URI prefix of the name " + jcrName
+ " is neither a valid URI nor a valid part"
+ " of a local name.");
}
} 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;
}
trailingSpaces = false;
} 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;
}
trailingSpaces = false;
}
}
// 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)) {
throw new IllegalArgumentException("Local name may not contain ':' nor '/'");
}
if (nameStart == len || state == STATE_NAME_START) {
throw new IllegalArgumentException("Local name must not be empty");
}
if (trailingSpaces) {
throw new IllegalArgumentException("Trailing spaces not allowed");
}
}