]> git.argeo.org Git - lgpl/argeo-commons.git/blob - AbstractContent.java
54d7410155961e6f1522f88fff4a1eddf7509e97
[lgpl/argeo-commons.git] / AbstractContent.java
1 package org.argeo.cms.acr;
2
3 import java.util.AbstractMap;
4 import java.util.AbstractSet;
5 import java.util.ArrayList;
6 import java.util.Collections;
7 import java.util.Iterator;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Optional;
11 import java.util.Set;
12
13 import javax.xml.namespace.QName;
14
15 import org.argeo.api.acr.Content;
16 import org.argeo.api.acr.CrAttributeType;
17 import org.argeo.api.acr.CrName;
18 import org.argeo.api.acr.NamespaceUtils;
19 import org.argeo.api.acr.spi.ProvidedContent;
20 import org.argeo.api.acr.spi.ProvidedSession;
21 import org.argeo.cms.util.LangUtils;
22
23 /** Partial reference implementation of a {@link ProvidedContent}. */
24 public abstract class AbstractContent extends AbstractMap<QName, Object> implements ProvidedContent {
25 private final ProvidedSession session;
26
27 // cache
28 // private String _path = null;
29
30 public AbstractContent(ProvidedSession session) {
31 this.session = session;
32 }
33
34 /*
35 * ATTRIBUTES OPERATIONS
36 */
37 // protected abstract Iterable<QName> keys();
38 //
39 // protected abstract void removeAttr(QName key);
40
41 @Override
42 public Set<Entry<QName, Object>> entrySet() {
43 Set<Entry<QName, Object>> result = new AttrSet();
44 return result;
45 }
46
47 @Override
48 public Class<?> getType(QName key) {
49 return String.class;
50 }
51
52 @Override
53 public boolean isMultiple(QName key) {
54 return false;
55 }
56
57 @SuppressWarnings("unchecked")
58 @Override
59 public <A> List<A> getMultiple(QName key, Class<A> clss) {
60 Object value = get(key);
61 if (value == null)
62 return new ArrayList<>();
63 if (value instanceof List) {
64 if (clss.isAssignableFrom(Object.class))
65 return (List<A>) value;
66 List<A> res = new ArrayList<>();
67 List<?> lst = (List<?>) value;
68 for (Object o : lst) {
69 A item = CrAttributeType.cast(clss, o).get();
70 res.add(item);
71 }
72 return res;
73 } else {// singleton
74 A res = CrAttributeType.cast(clss, value).get();
75 return Collections.singletonList(res);
76 }
77 }
78
79 /*
80 * CONTENT OPERATIONS
81 */
82
83 @Override
84 public String getPath() {
85 // if (_path != null)
86 // return _path;
87 List<Content> ancestors = new ArrayList<>();
88 collectAncestors(ancestors, this);
89 StringBuilder path = new StringBuilder();
90 ancestors: for (Content c : ancestors) {
91 QName name = c.getName();
92 if (CrName.root.qName().equals(name))
93 continue ancestors;
94
95 path.append('/');
96 path.append(NamespaceUtils.toPrefixedName(name));
97 int siblingIndex = c.getSiblingIndex();
98 if (siblingIndex != 1)
99 path.append('[').append(siblingIndex).append(']');
100 }
101 // _path = path.toString();
102 // return _path;
103 return path.toString();
104 }
105
106 private void collectAncestors(List<Content> ancestors, Content content) {
107 if (content == null)
108 return;
109 ancestors.add(0, content);
110 collectAncestors(ancestors, content.getParent());
111 }
112
113 @Override
114 public int getDepth() {
115 List<Content> ancestors = new ArrayList<>();
116 collectAncestors(ancestors, this);
117 return ancestors.size();
118 }
119
120 @Override
121 public boolean isRoot() {
122 return CrName.root.qName().equals(getName());
123 }
124
125 @Override
126 public String getSessionLocalId() {
127 return getPath();
128 }
129
130 /*
131 * SESSION
132 */
133
134 @Override
135 public ProvidedSession getSession() {
136 return session;
137 }
138
139 /*
140 * TYPING
141 */
142
143 @Override
144 public List<QName> getContentClasses() {
145 return new ArrayList<>();
146 }
147
148 /*
149 * UTILITIES
150 */
151 // protected boolean isDefaultAttrTypeRequested(Class<?> clss) {
152 // // check whether clss is Object.class
153 // return clss.isAssignableFrom(Object.class);
154 // }
155
156 // @Override
157 // public String toString() {
158 // return "content " + getPath();
159 // }
160
161 /*
162 * DEFAULTS
163 */
164 // - no children
165 // - no attributes
166 // - cannot be modified
167 @Override
168 public Iterator<Content> iterator() {
169 return Collections.emptyIterator();
170 }
171
172 @Override
173 public Content add(QName name, QName... classes) {
174 throw new UnsupportedOperationException("Content cannot be added.");
175 }
176
177 @Override
178 public void remove() {
179 throw new UnsupportedOperationException("Content cannot be removed.");
180 }
181
182 protected Iterable<QName> keys() {
183 return Collections.emptySet();
184 }
185
186 @Override
187 public <A> Optional<A> get(QName key, Class<A> clss) {
188 return Optional.empty();
189 }
190
191 protected void removeAttr(QName key) {
192 throw new UnsupportedOperationException("Attributes cannot be removed.");
193 }
194
195 /*
196 * SUB CLASSES
197 */
198
199 class AttrSet extends AbstractSet<Entry<QName, Object>> {
200
201 @Override
202 public Iterator<Entry<QName, Object>> iterator() {
203 final Iterator<QName> keys = keys().iterator();
204 Iterator<Entry<QName, Object>> it = new Iterator<Map.Entry<QName, Object>>() {
205
206 QName key = null;
207
208 @Override
209 public boolean hasNext() {
210 return keys.hasNext();
211 }
212
213 @Override
214 public Entry<QName, Object> next() {
215 key = keys.next();
216 // TODO check type
217 Optional<?> value = get(key, Object.class);
218 assert !value.isEmpty();
219 AbstractMap.SimpleEntry<QName, Object> entry = new SimpleEntry<>(key, value.get());
220 return entry;
221 }
222
223 @Override
224 public void remove() {
225 if (key != null) {
226 AbstractContent.this.removeAttr(key);
227 } else {
228 throw new IllegalStateException("Iteration has not started");
229 }
230 }
231
232 };
233 return it;
234 }
235
236 @Override
237 public int size() {
238 return LangUtils.size(keys());
239 }
240
241 }
242
243 /*
244 * OBJECT METHODS
245 */
246 @Override
247 public String toString() {
248 return "content " + getPath();
249 }
250 }