]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.api.acr/src/org/argeo/api/acr/Content.java
Cast to UUID
[lgpl/argeo-commons.git] / org.argeo.api.acr / src / org / argeo / api / acr / Content.java
1 package org.argeo.api.acr;
2
3 import static org.argeo.api.acr.NamespaceUtils.unqualified;
4
5 import java.io.Closeable;
6 import java.io.IOException;
7 import java.util.ArrayList;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Optional;
11 import java.util.concurrent.CompletableFuture;
12
13 import javax.xml.namespace.QName;
14
15 /**
16 * A semi-structured content, with attributes, within a hierarchical structure.
17 */
18 public interface Content extends Iterable<Content>, Map<QName, Object> {
19 /** The base of a repository path. */
20 String ROOT_PATH = "/";
21
22 QName getName();
23
24 String getPath();
25
26 Content getParent();
27
28 /*
29 * ATTRIBUTES OPERATIONS
30 */
31
32 <A> Optional<A> get(QName key, Class<A> clss);
33
34 Class<?> getType(QName key);
35
36 boolean isMultiple(QName key);
37
38 <A> List<A> getMultiple(QName key, Class<A> clss);
39
40 /*
41 * ATTRIBUTES OPERATION HELPERS
42 */
43 default boolean containsKey(QNamed key) {
44 return containsKey(key.qName());
45 }
46
47 default <A> Optional<A> get(QNamed key, Class<A> clss) {
48 return get(key.qName(), clss);
49 }
50
51 default Object get(QNamed key) {
52 return get(key.qName());
53 }
54
55 default Object put(QNamed key, Object value) {
56 return put(key.qName(), value);
57 }
58
59 default Object remove(QNamed key) {
60 return remove(key.qName());
61 }
62
63 // TODO do we really need the helpers below?
64
65 default Object get(String key) {
66 return get(unqualified(key));
67 }
68
69 default Object put(String key, Object value) {
70 return put(unqualified(key), value);
71 }
72
73 default Object remove(String key) {
74 return remove(unqualified(key));
75 }
76
77 @SuppressWarnings("unchecked")
78 default <A> List<A> getMultiple(QName key) {
79 Class<A> type;
80 try {
81 type = (Class<A>) getType(key);
82 } catch (ClassCastException e) {
83 throw new IllegalArgumentException("Requested type is not the default type");
84 }
85 List<A> res = getMultiple(key, type);
86 return res;
87 }
88
89 /*
90 * CONTENT OPERATIONS
91 */
92 Content add(QName name, QName... classes);
93
94 default Content add(String name, QName... classes) {
95 return add(unqualified(name), classes);
96 }
97
98 void remove();
99
100 /*
101 * TYPING
102 */
103 List<QName> getContentClasses();
104
105 default void addContentClasses(QName... contentClass) {
106 throw new UnsupportedOperationException("Adding content classes to " + getPath() + " is not supported");
107 }
108
109 /** AND */
110 default boolean isContentClass(QName... contentClass) {
111 List<QName> contentClasses = getContentClasses();
112 for (QName cClass : contentClass) {
113 if (!contentClasses.contains(cClass))
114 return false;
115 }
116 return true;
117 }
118
119 /** AND */
120 default boolean isContentClass(QNamed... contentClass) {
121 List<QName> lst = new ArrayList<>();
122 for (QNamed qNamed : contentClass)
123 lst.add(qNamed.qName());
124 return isContentClass(lst.toArray(new QName[lst.size()]));
125 }
126
127 /** OR */
128 default boolean hasContentClass(QName... contentClass) {
129 List<QName> contentClasses = getContentClasses();
130 for (QName cClass : contentClass) {
131 if (contentClasses.contains(cClass))
132 return true;
133 }
134 return false;
135 }
136
137 /** OR */
138 default boolean hasContentClass(QNamed... contentClass) {
139 List<QName> lst = new ArrayList<>();
140 for (QNamed qNamed : contentClass)
141 lst.add(qNamed.qName());
142 return hasContentClass(lst.toArray(new QName[lst.size()]));
143 }
144
145 /*
146 * SIBLINGS
147 */
148
149 default int getSiblingIndex() {
150 return 1;
151 }
152
153 /*
154 * DEFAULT METHODS
155 */
156 default <A> A adapt(Class<A> clss) {
157 throw new UnsupportedOperationException("Cannot adapt content " + this + " to " + clss.getName());
158 }
159
160 default <C extends Closeable> C open(Class<C> clss) throws IOException {
161 throw new UnsupportedOperationException("Cannot open content " + this + " as " + clss.getName());
162 }
163
164 default <A> CompletableFuture<A> write(Class<A> clss) {
165 throw new UnsupportedOperationException("Cannot write content " + this + " as " + clss.getName());
166 }
167
168 /*
169 * CHILDREN
170 */
171
172 default boolean hasChild(QName name) {
173 for (Content child : this) {
174 if (child.getName().equals(name))
175 return true;
176 }
177 return false;
178 }
179
180 default boolean hasChild(QNamed name) {
181 return hasChild(name.qName());
182 }
183
184 default Content anyOrAddChild(QName name, QName... classes) {
185 Content child = anyChild(name);
186 if (child != null)
187 return child;
188 return this.add(name, classes);
189 }
190
191 default Content anyOrAddChild(String name, QName... classes) {
192 return anyOrAddChild(unqualified(name), classes);
193 }
194
195 /** Any child with this name, or null if there is none */
196 default Content anyChild(QName name) {
197 for (Content child : this) {
198 if (child.getName().equals(name))
199 return child;
200 }
201 return null;
202 }
203
204 default List<Content> children(QName name) {
205 List<Content> res = new ArrayList<>();
206 for (Content child : this) {
207 if (child.getName().equals(name))
208 res.add(child);
209 }
210 return res;
211 }
212
213 default List<Content> children(QNamed name) {
214 return children(name.qName());
215 }
216
217 default Optional<Content> soleChild(QNamed name) {
218 return soleChild(name.qName());
219 }
220
221 default Optional<Content> soleChild(QName name) {
222 List<Content> res = children(name);
223 if (res.isEmpty())
224 return Optional.empty();
225 if (res.size() > 1)
226 throw new IllegalStateException(this + " has multiple children with name " + name);
227 return Optional.of(res.get(0));
228 }
229
230 default Content child(QName name) {
231 return soleChild(name).orElseThrow();
232 }
233
234 default Content child(QNamed name) {
235 return child(name.qName());
236 }
237
238 /*
239 * ATTR AS STRING
240 */
241 /**
242 * Convenience method returning an attribute as a {@link String}.
243 *
244 * @param key the attribute name
245 * @return the attribute value as a {@link String} or <code>null</code>.
246 *
247 * @see Object#toString()
248 */
249 default String attr(QName key) {
250 return get(key, String.class).orElse(null);
251 }
252
253 /**
254 * Convenience method returning an attribute as a {@link String}.
255 *
256 * @param key the attribute name
257 * @return the attribute value as a {@link String} or <code>null</code>.
258 *
259 * @see Object#toString()
260 */
261 default String attr(QNamed key) {
262 return attr(key.qName());
263 }
264
265 /**
266 * Convenience method returning an attribute as a {@link String}.
267 *
268 * @param key the attribute name
269 * @return the attribute value as a {@link String} or <code>null</code>.
270 *
271 * @see Object#toString()
272 */
273 default String attr(String key) {
274 return attr(unqualified(key));
275 }
276
277 /*
278 * CONTEXT
279 */
280 /**
281 * A content within this repository
282 *
283 * @param path either an absolute path or a path relative to this content
284 */
285 Optional<Content> getContent(String path);
286
287 /*
288 * EXPERIMENTAL UNSUPPORTED
289 */
290 default boolean hasText() {
291 return false;
292 }
293
294 default String getText() {
295 throw new UnsupportedOperationException();
296 }
297
298 }