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