]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.api.acr/src/org/argeo/api/acr/CrAttributeType.java
Introduce system roles
[lgpl/argeo-commons.git] / org.argeo.api.acr / src / org / argeo / api / acr / CrAttributeType.java
1 package org.argeo.api.acr;
2
3 import java.net.URI;
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;
9 import java.util.List;
10 import java.util.UUID;
11
12 import javax.xml.XMLConstants;
13
14 /**
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
17 * <code>String<code>.
18 */
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()), //
30 ;
31
32 private final Class<?> clss;
33 private final AttributeFormatter<?> formatter;
34
35 private <T> CrAttributeType(Class<T> clss, AttributeFormatter<T> formatter) {
36 this.clss = clss;
37 this.formatter = formatter;
38 }
39
40 public Class<?> getClss() {
41 return clss;
42 }
43
44 public AttributeFormatter<?> getFormatter() {
45 return formatter;
46 }
47
48 @Override
49 public String getDefaultPrefix() {
50 if (equals(UUID))
51 return CrName.CR_DEFAULT_PREFIX;
52 else
53 return "xs";
54 }
55
56 @Override
57 public String getNamespaceURI() {
58 if (equals(UUID))
59 return CrName.CR_NAMESPACE_URI;
60 else
61 return XMLConstants.W3C_XML_SCHEMA_NS_URI;
62 }
63
64 /** Default parsing procedure from a String to an object. */
65 public static Object parse(String str) {
66 if (str == null)
67 throw new IllegalArgumentException("String cannot be null");
68 // order IS important
69 try {
70 if (str.length() == 4 || str.length() == 5)
71 return BOOLEAN.getFormatter().parse(str);
72 } catch (IllegalArgumentException e) {
73 // silent
74 }
75 try {
76 return INTEGER.getFormatter().parse(str);
77 } catch (IllegalArgumentException e) {
78 // silent
79 }
80 try {
81 return LONG.getFormatter().parse(str);
82 } catch (IllegalArgumentException e) {
83 // silent
84 }
85 try {
86 return DOUBLE.getFormatter().parse(str);
87 } catch (IllegalArgumentException e) {
88 // silent
89 }
90 try {
91 return DATE_TIME.getFormatter().parse(str);
92 } catch (IllegalArgumentException e) {
93 // silent
94 }
95 try {
96 if (str.length() == 36)
97 return UUID.getFormatter().parse(str);
98 } catch (IllegalArgumentException e) {
99 // silent
100 }
101 try {
102 java.net.URI uri = (java.net.URI) ANY_URI.getFormatter().parse(str);
103 if (uri.getScheme() != null)
104 return uri;
105 String path = uri.getPath();
106 if (path.indexOf('/') >= 0)
107 return uri;
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) {
113 // silent
114 }
115
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
118
119 // default
120 return STRING.getFormatter().parse(str);
121 }
122
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");
133
134 String base64Str = schemeSpecificPart.substring(commaIndex + 1);
135 return Base64.getDecoder().decode(base64Str);
136
137 }
138
139 /** Utility to convert bytes to a data: URI. */
140 public static URI bytesToDataURI(byte[] arr) {
141 String base64Str = Base64.getEncoder().encodeToString(arr);
142 try {
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);
147 }
148
149 }
150
151 static class BooleanFormatter implements AttributeFormatter<Boolean> {
152
153 /**
154 * @param str must be exactly equals to either 'true' or 'false' (different
155 * contract than {@link Boolean#parseBoolean(String)}.
156 */
157 @Override
158 public Boolean parse(String str) throws IllegalArgumentException {
159 if ("true".equals(str))
160 return Boolean.TRUE;
161 if ("false".equals(str))
162 return Boolean.FALSE;
163 throw new IllegalArgumentException("Argument is neither 'true' or 'false' : " + str);
164 }
165 }
166
167 static class IntegerFormatter implements AttributeFormatter<Integer> {
168 @Override
169 public Integer parse(String str) throws NumberFormatException {
170 return Integer.parseInt(str);
171 }
172 }
173
174 static class LongFormatter implements AttributeFormatter<Long> {
175 @Override
176 public Long parse(String str) throws NumberFormatException {
177 return Long.parseLong(str);
178 }
179 }
180
181 static class DoubleFormatter implements AttributeFormatter<Double> {
182
183 @Override
184 public Double parse(String str) throws NumberFormatException {
185 return Double.parseDouble(str);
186 }
187 }
188
189 static class InstantFormatter implements AttributeFormatter<Instant> {
190
191 @Override
192 public Instant parse(String str) throws IllegalArgumentException {
193 try {
194 return Instant.parse(str);
195 } catch (DateTimeParseException e) {
196 throw new IllegalArgumentException("Cannot parse '" + str + "' as an instant", e);
197 }
198 }
199 }
200
201 static class UuidFormatter implements AttributeFormatter<UUID> {
202
203 @Override
204 public UUID parse(String str) throws IllegalArgumentException {
205 return java.util.UUID.fromString(str);
206 }
207 }
208
209 static class UriFormatter implements AttributeFormatter<URI> {
210
211 @Override
212 public URI parse(String str) throws IllegalArgumentException {
213 try {
214 return new URI(str);
215 } catch (URISyntaxException e) {
216 throw new IllegalArgumentException("Cannot parse " + str + " as an URI.", e);
217 }
218 }
219
220 }
221
222 static class StringFormatter implements AttributeFormatter<String> {
223
224 @Override
225 public String parse(String str) {
226 return str;
227 }
228
229 @Override
230 public String format(String obj) {
231 return obj;
232 }
233
234 }
235
236 }