1 package org
.argeo
.api
.acr
;
4 import java
.net
.URISyntaxException
;
5 import java
.time
.Instant
;
6 import java
.time
.format
.DateTimeParseException
;
7 import java
.util
.Arrays
;
8 import java
.util
.Base64
;
10 import java
.util
.UUID
;
12 import javax
.xml
.XMLConstants
;
15 * Minimal standard attribute types that MUST be supported. All related classes
16 * belong to java.base and can be implicitly derived form a given
19 public enum CrAttributeType
implements ContentNameSupplier
{
20 BOOLEAN(Boolean
.class, new BooleanFormatter()), //
21 INTEGER(Integer
.class, new IntegerFormatter()), //
22 LONG(Long
.class, new LongFormatter()), //
23 DOUBLE(Double
.class, new DoubleFormatter()), //
24 // we do not support short and float, like recent additions to Java
25 // (e.g. optional primitives)
26 DATE_TIME(Instant
.class, new InstantFormatter()), //
27 UUID(UUID
.class, new UuidFormatter()), //
28 ANY_URI(URI
.class, new UriFormatter()), //
29 STRING(String
.class, new StringFormatter()), //
32 private final Class
<?
> clss
;
33 private final AttributeFormatter
<?
> formatter
;
35 private <T
> CrAttributeType(Class
<T
> clss
, AttributeFormatter
<T
> formatter
) {
37 this.formatter
= formatter
;
40 public Class
<?
> getClss() {
44 public AttributeFormatter
<?
> getFormatter() {
49 public String
getDefaultPrefix() {
51 return CrName
.CR_DEFAULT_PREFIX
;
57 public String
getNamespaceURI() {
59 return CrName
.CR_NAMESPACE_URI
;
61 return XMLConstants
.W3C_XML_SCHEMA_NS_URI
;
64 /** Default parsing procedure from a String to an object. */
65 public static Object
parse(String str
) {
67 throw new IllegalArgumentException("String cannot be null");
70 if (str
.length() == 4 || str
.length() == 5)
71 return BOOLEAN
.getFormatter().parse(str
);
72 } catch (IllegalArgumentException e
) {
76 return INTEGER
.getFormatter().parse(str
);
77 } catch (IllegalArgumentException e
) {
81 return LONG
.getFormatter().parse(str
);
82 } catch (IllegalArgumentException e
) {
86 return DOUBLE
.getFormatter().parse(str
);
87 } catch (IllegalArgumentException e
) {
91 return DATE_TIME
.getFormatter().parse(str
);
92 } catch (IllegalArgumentException e
) {
96 if (str
.length() == 36)
97 return UUID
.getFormatter().parse(str
);
98 } catch (IllegalArgumentException e
) {
102 java
.net
.URI uri
= (java
.net
.URI
) ANY_URI
.getFormatter().parse(str
);
103 if (uri
.getScheme() != null)
105 String path
= uri
.getPath();
106 if (path
.indexOf('/') >= 0)
108 // if it is not clearly a path, we will consider it as a string
109 // because their is no way to distinguish between 'any_string'
110 // and 'any_file_name'.
111 // Note that providing ./any_file_name would result in an equivalent URI
112 } catch (IllegalArgumentException e
) {
116 // TODO support QName as a type? It would require a NamespaceContext
117 // see https://www.oreilly.com/library/view/xml-schema/0596002521/re91.html
120 return STRING
.getFormatter().parse(str
);
123 /** Utility to convert a data: URI to bytes. */
124 public static byte[] bytesFromDataURI(URI uri
) {
125 if (!"data".equals(uri
.getScheme()))
126 throw new IllegalArgumentException("URI must have 'data' as a scheme");
127 String schemeSpecificPart
= uri
.getSchemeSpecificPart();
128 int commaIndex
= schemeSpecificPart
.indexOf(',');
129 String prefix
= schemeSpecificPart
.substring(0, commaIndex
);
130 List
<String
> info
= Arrays
.asList(prefix
.split(";"));
131 if (!info
.contains("base64"))
132 throw new IllegalArgumentException("URI must specify base64");
134 String base64Str
= schemeSpecificPart
.substring(commaIndex
+ 1);
135 return Base64
.getDecoder().decode(base64Str
);
139 /** Utility to convert bytes to a data: URI. */
140 public static URI
bytesToDataURI(byte[] arr
) {
141 String base64Str
= Base64
.getEncoder().encodeToString(arr
);
143 final String PREFIX
= "data:application/octet-stream;base64,";
144 return new URI(PREFIX
+ base64Str
);
145 } catch (URISyntaxException e
) {
146 throw new IllegalStateException("Cannot serialize bytes a Base64 data URI", e
);
151 static class BooleanFormatter
implements AttributeFormatter
<Boolean
> {
154 * @param str must be exactly equals to either 'true' or 'false' (different
155 * contract than {@link Boolean#parseBoolean(String)}.
158 public Boolean
parse(String str
) throws IllegalArgumentException
{
159 if ("true".equals(str
))
161 if ("false".equals(str
))
162 return Boolean
.FALSE
;
163 throw new IllegalArgumentException("Argument is neither 'true' or 'false' : " + str
);
167 static class IntegerFormatter
implements AttributeFormatter
<Integer
> {
169 public Integer
parse(String str
) throws NumberFormatException
{
170 return Integer
.parseInt(str
);
174 static class LongFormatter
implements AttributeFormatter
<Long
> {
176 public Long
parse(String str
) throws NumberFormatException
{
177 return Long
.parseLong(str
);
181 static class DoubleFormatter
implements AttributeFormatter
<Double
> {
184 public Double
parse(String str
) throws NumberFormatException
{
185 return Double
.parseDouble(str
);
189 static class InstantFormatter
implements AttributeFormatter
<Instant
> {
192 public Instant
parse(String str
) throws IllegalArgumentException
{
194 return Instant
.parse(str
);
195 } catch (DateTimeParseException e
) {
196 throw new IllegalArgumentException("Cannot parse '" + str
+ "' as an instant", e
);
201 static class UuidFormatter
implements AttributeFormatter
<UUID
> {
204 public UUID
parse(String str
) throws IllegalArgumentException
{
205 return java
.util
.UUID
.fromString(str
);
209 static class UriFormatter
implements AttributeFormatter
<URI
> {
212 public URI
parse(String str
) throws IllegalArgumentException
{
215 } catch (URISyntaxException e
) {
216 throw new IllegalArgumentException("Cannot parse " + str
+ " as an URI.", e
);
222 static class StringFormatter
implements AttributeFormatter
<String
> {
225 public String
parse(String str
) {
230 public String
format(String obj
) {