View Javadoc
1   package org.openehealth.ipf.commons.core;
2   
3   import java.io.Serializable;
4   import java.io.UnsupportedEncodingException;
5   import java.net.URI;
6   import java.net.URISyntaxException;
7   import java.net.URLDecoder;
8   import java.util.Locale;
9   import java.util.UUID;
10  import java.util.regex.Pattern;
11  
12  /**
13   * URN abstraction, following the pattern of URI and URL classes. This is not meant as a generic
14   * URN representation as defined in RFC 2141, but limited to its uses in healthcare domain,
15   * specifically for encoding UUIDs and OIDs.
16   *
17   * Note that in URNs the namespace identifier is case-insensitive
18   */
19  public final class URN implements Comparable<URN>, Serializable {
20  
21      public static final String UUID = "uuid";
22      public static final String OID = "oid";
23      public static final String PIN = "pin";
24      private static final String PREFIX = "urn";
25      private static final String SEP = ":";
26      private static final Pattern REGEX = Pattern.compile("^urn:[A-Za-z0-9][A-Za-z0-9-]{0,31}:[A-Za-z0-9()+,\\-.:=@;$_!*'%/?#]+$");
27  
28      private final URI uri;
29  
30      public URN(String text) throws URISyntaxException {
31          if (!REGEX.matcher(text).matches()) {
32              throw new URISyntaxException(text, "Not a valid URN");
33          }
34          this.uri = URI.create(text);
35      }
36  
37      public static URN create(String text) throws URISyntaxException {
38          return new URN(text);
39      }
40  
41      public URN(URI uri) throws URISyntaxException {
42          this(uri.toString());
43      }
44  
45      public URN(UUID uuid) throws URISyntaxException {
46          this(String.format("%s%s%s%2$s%s", PREFIX, SEP, UUID, uuid.toString()));
47      }
48  
49      public URN(String namespaceId, String namespaceSpecificString) throws URISyntaxException {
50          this(String.format("%s%s%s%2$s%s", PREFIX, SEP, namespaceId, namespaceSpecificString));
51      }
52  
53      @Override
54      public int compareTo(URN urn) {
55          return equals(urn) ? 0 : uri.compareTo(urn.uri);
56      }
57  
58      @Override
59      public boolean equals(Object o) {
60          if (this == o) return true;
61          if (o == null || getClass() != o.getClass()) return false;
62          URN urn = (URN) o;
63          return getNamespaceId().equalsIgnoreCase(urn.getNamespaceId()) &&
64                  getNamespaceSpecificString().equals(urn.getNamespaceSpecificString());
65      }
66  
67      @Override
68      public int hashCode() {
69          int result = getNamespaceId().toLowerCase(Locale.ROOT).hashCode();
70          result = 31 * result + getNamespaceSpecificString().hashCode();
71          return result;
72      }
73  
74      public static boolean isURN(final String text) {
75          try {
76              new URN(text);
77              return true;
78          } catch (URISyntaxException ex) {
79              return false;
80          }
81      }
82  
83      /**
84       * @return a new URI object representing this URN
85       */
86      public URI toURI() {
87          return URI.create(uri.toString());
88      }
89  
90      /**
91       * @return the namespace ID of the URN
92       */
93      public String getNamespaceId() {
94          return this.part(1);
95      }
96  
97      public boolean isNamespace(String namespace) {
98          return getNamespaceId().equalsIgnoreCase(namespace);
99      }
100 
101     /**
102      * @return namespace-specific string, i.e. an OID or UUID value
103      */
104     public String getNamespaceSpecificString() {
105         try {
106             return URLDecoder.decode(this.part(2), "UTF-8");
107         } catch (UnsupportedEncodingException ex) {
108             throw new IllegalStateException(ex);
109         }
110     }
111 
112     @Override
113     public String toString() {
114         return uri.toString();
115     }
116 
117     private String part(final int index) {
118         return uri.toString().split(SEP, 3)[index];
119     }
120 }