1 package org
.argeo
.api
.acr
;
3 import static java
.nio
.charset
.StandardCharsets
.UTF_8
;
5 import java
.nio
.charset
.StandardCharsets
;
6 import java
.util
.Collections
;
8 import java
.util
.Objects
;
9 import java
.util
.TreeMap
;
10 import java
.util
.UUID
;
12 import javax
.xml
.XMLConstants
;
13 import javax
.xml
.namespace
.NamespaceContext
;
14 import javax
.xml
.namespace
.QName
;
17 * A {@link QName} which MUST have prefix and whose {@link #toString()} method
18 * returns the prefixed form (prefix:localPart).
20 public class ContentName
extends QName
{
21 private static final long serialVersionUID
= 5722920985400306100L;
22 public final static UUID NIL_UUID
= UUID
.fromString("00000000-0000-0000-0000-000000000000");
24 * The UUID v3 of http://www.w3.org/2000/xmlns/ within the standard DNS
25 * namespace, to be used as a base for the namespaces.
27 * @see https://www.w3.org/TR/xml-names/#ns-decl
29 // uuidgen --md5 --namespace @dns --name http://www.w3.org/2000/xmlns/
30 // NOTE : must be declared before default namespaces
31 public final static UUID XMLNS_UUID
= UUID
.fromString("4b352aad-ba1c-3139-b9d3-41e5816f6088");
32 // uuidgen --md5 --namespace 4b352aad-ba1c-3139-b9d3-41e5816f6088 --name ""
33 public final static UUID NULL_NS_UUID
= UUID
.fromString("f07726e3-99c8-3178-b758-a86ed41f300d");
35 private final static Map
<String
, UUID
> namespaceUuids
= Collections
.synchronizedMap(new TreeMap
<>());
36 private final static Map
<String
, UUID
> nameUuids
= Collections
.synchronizedMap(new TreeMap
<>());
39 assert NULL_NS_UUID
.equals(nameUUIDv3(XMLNS_UUID
, XMLConstants
.NULL_NS_URI
.getBytes(UTF_8
)));
42 // private final UUID uuid;
44 public ContentName(String namespaceURI
, String localPart
, NamespaceContext nsContext
) {
45 super(namespaceURI
, localPart
, checkPrefix(nsContext
, namespaceURI
));
48 private static String
checkPrefix(NamespaceContext nsContext
, String namespaceURI
) {
49 Objects
.requireNonNull(nsContext
, "Namespace context cannot be null");
50 Objects
.requireNonNull(namespaceURI
, "Namespace URI cannot be null");
51 String prefix
= nsContext
.getNamespaceURI(namespaceURI
);
53 throw new IllegalStateException("No prefix found for " + namespaceURI
+ " from context " + nsContext
);
57 ContentName(String namespaceURI
, String localPart
, String prefix
) {
58 super(namespaceURI
, localPart
, prefix
);
61 public ContentName(String localPart
) {
62 super(XMLConstants
.NULL_NS_URI
, localPart
, XMLConstants
.DEFAULT_NS_PREFIX
);
65 public ContentName(QName qName
, NamespaceContext nsContext
) {
66 this(qName
.getNamespaceURI(), qName
.getLocalPart(), nsContext
);
69 public String
toQNameString() {
70 return super.toString();
73 public String
toPrefixedString() {
74 return toPrefixedString(this);
82 public String
toString() {
83 return toPrefixedString();
87 protected Object
clone() throws CloneNotSupportedException
{
88 return new ContentName(getNamespaceURI(), getLocalPart(), getPrefix());
91 public static String
toPrefixedString(QName name
) {
92 String prefix
= name
.getPrefix();
93 assert prefix
!= null;
94 return "".equals(prefix
) ? name
.getLocalPart() : prefix
+ ":" + name
.getLocalPart();
96 // ContentNamespace getNamespace();
100 public static UUID
namespaceUuid(String namespaceURI
) {
101 if (XMLConstants
.NULL_NS_URI
.equals(namespaceURI
))
103 Objects
.requireNonNull(namespaceURI
, "Namespace URI cannot be null");
104 synchronized (namespaceUuids
) {
105 UUID namespaceUuid
= namespaceUuids
.get(namespaceURI
);
106 if (namespaceUuid
== null) {
107 namespaceUuid
= nameUUIDv3(ContentName
.XMLNS_UUID
,
108 namespaceURI
.toString().getBytes(StandardCharsets
.UTF_8
));
109 namespaceUuids
.put(namespaceURI
, namespaceUuid
);
111 return namespaceUuid
;
115 public static UUID
nameUuid(String namespaceURI
, QName name
) {
116 return nameUuid(name
.getNamespaceURI(), name
.getLocalPart());
119 public static UUID
nameUuid(String namespaceURI
, String name
) {
120 Objects
.requireNonNull(namespaceURI
, "Namespace cannot be null");
121 Objects
.requireNonNull(name
, "Name cannot be null");
122 synchronized (nameUuids
) {
123 String key
= XMLConstants
.NULL_NS_URI
.equals(namespaceURI
) ? name
: "{" + namespaceURI
+ "}" + name
;
124 UUID nameUuid
= nameUuids
.get(key
);
125 if (nameUuid
== null) {
126 UUID namespaceUuid
= namespaceUuid(namespaceURI
);
127 nameUuid
= nameUUIDv3(namespaceUuid
, name
.getBytes(StandardCharsets
.UTF_8
));
128 namespaceUuids
.put(key
, nameUuid
);
135 * CANONICAL IMPLEMENTATION based on java.util.UUID.nameUUIDFromBytes(byte[])
137 static UUID
nameUUIDv3(UUID namespace
, byte[] name
) {
138 byte[] arr
= new byte[name
.length
+ 16];
139 ContentName
.copyUuidBytes(namespace
, arr
, 0);
140 System
.arraycopy(name
, 0, arr
, 16, name
.length
);
141 return UUID
.nameUUIDFromBytes(arr
);
144 static void copyUuidBytes(UUID uuid
, byte[] arr
, int offset
) {
145 long msb
= uuid
.getMostSignificantBits();
146 long lsb
= uuid
.getLeastSignificantBits();
147 assert arr
.length
>= 16 + offset
;
148 for (int i
= offset
; i
< 8 + offset
; i
++)
149 arr
[i
] = (byte) ((msb
>> ((7 - i
) * 8)) & 0xff);
150 for (int i
= 8 + offset
; i
< 16 + offset
; i
++)
151 arr
[i
] = (byte) ((lsb
>> ((15 - i
) * 8)) & 0xff);
158 public static boolean contains(QName
[] classes
, QName name
) {
159 for (QName clss
: classes
) {
160 if (clss
.equals(name
))