Skip to content

Commit e512a3a

Browse files
committed
JCR-5152 Add method to check if a (local) name is valid according to JCR
spec
1 parent 0067cea commit e512a3a

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed

jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/Text.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.ArrayList;
2525
import java.util.BitSet;
2626
import java.util.Properties;
27+
import java.util.Set;
2728

2829
/**
2930
* This Class provides some text related utilities
@@ -41,6 +42,8 @@ private Text() {
4142
*/
4243
public static final char[] hexTable = "0123456789abcdef".toCharArray();
4344

45+
private static final Set<Character> INVALID_JCR_LOCAL_NAME_CHARS = Set.of( '/', ':', '[', ']', '*', '|');
46+
4447
/**
4548
* Calculate an MD5 hash of the string given.
4649
*
@@ -466,6 +469,10 @@ public static String unescape(String string) {
466469
* char ::= nonspace | ' '
467470
* nonspace ::= (* Any Unicode character except: '/', ':', '[', ']', '*', '|' or any whitespace character *)
468471
* </pre>
472+
* <p>
473+
* Note that just using this method does not necessarily return a string which is a
474+
* <a href="https://s.apache.org/jcr-2.0-spec/3_Repository_Model.html#3.2.2%20Local%20Names">valid local name</a>.
475+
* You still have to take care of invalid <a href="https://www.w3.org/TR/xml/#NT-Char">XML characters</a>.
469476
*
470477
* @param name the name to escape
471478
* @return the escaped name
@@ -567,6 +574,31 @@ public static String unescapeIllegalJcrChars(String name) {
567574
return buffer.toString();
568575
}
569576

577+
/**
578+
* Checks if the given name is a valid JCR local name.
579+
* <p>
580+
* Note that the return value of {@link #escapeIllegalJcrChars(String)} is not necessarily a valid local name.
581+
* You still have to take care of invalid <a href="https://www.w3.org/TR/xml/#NT-Char">XML characters</a>.
582+
*
583+
* @param localName the string value to check
584+
* @return <code>true</code> if the name is valid, <code>false</code> otherwise.
585+
* @see <a href="https://s.apache.org/jcr-2.0-spec/3_Repository_Model.html#3.2.2%20Local%20Names">JCR 2.0 Spec, §3.2.2 Local Names</a>
586+
* @see #escapeIllegalJcrChars(String)
587+
* @since 2.6.0 (Apache Jackrabbit 2.24.0)
588+
*/
589+
public static boolean isValidJcrLocalName(String localName) {
590+
if (localName == null || localName.isEmpty()) {
591+
return false;
592+
}
593+
// self or parent are invalid
594+
if (localName.equals(".") || localName.equals("..")) {
595+
return false;
596+
}
597+
return localName.chars().noneMatch(c ->
598+
INVALID_JCR_LOCAL_NAME_CHARS.contains((char) c) || !XMLChar.isValid(c)
599+
);
600+
}
601+
570602
/**
571603
* Returns the name part of the path. If the given path is already a name
572604
* (i.e. contains no slashes) it is returned.

jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/package-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@
1414
* See the License for the specific language governing permissions and
1515
* limitations under the License.
1616
*/
17-
@org.osgi.annotation.versioning.Version("2.5.0")
17+
@org.osgi.annotation.versioning.Version("2.6.0")
1818
package org.apache.jackrabbit.util;

jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/TextTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,4 +202,14 @@ public void testEscapeXML() {
202202
public void testEscapeHTML() {
203203
assertEquals("&amp;&lt;&gt;&#39;&quot;", Text.encodeIllegalHTMLCharacters("&<>'\""));
204204
}
205+
206+
public void testIsValidJcrLocalName() {
207+
assertTrue(Text.isValidJcrLocalName("valid%Name..\n\r test.\"'"));
208+
assertFalse(Text.isValidJcrLocalName("invalid|name"));
209+
assertFalse(Text.isValidJcrLocalName("some:name"));
210+
// containing non XML characters (unicode control character)
211+
assertFalse(Text.isValidJcrLocalName("\u000FinvalidName"));
212+
assertFalse(Text.isValidJcrLocalName(".."));
213+
assertFalse(Text.isValidJcrLocalName("."));
214+
}
205215
}

0 commit comments

Comments
 (0)