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