]> git.argeo.org Git - lgpl/argeo-commons.git/blob - acr/JcrContent.java
Prepare next development cycle
[lgpl/argeo-commons.git] / acr / JcrContent.java
1 package org.argeo.cms.jcr.acr;
2
3 import java.io.Closeable;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.PipedInputStream;
7 import java.io.PipedOutputStream;
8 import java.util.ArrayList;
9 import java.util.Calendar;
10 import java.util.HashSet;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.Optional;
14 import java.util.Set;
15 import java.util.concurrent.ForkJoinPool;
16
17 import javax.jcr.Node;
18 import javax.jcr.NodeIterator;
19 import javax.jcr.Property;
20 import javax.jcr.PropertyIterator;
21 import javax.jcr.PropertyType;
22 import javax.jcr.RepositoryException;
23 import javax.jcr.Value;
24 import javax.jcr.nodetype.NodeType;
25 import javax.xml.namespace.QName;
26 import javax.xml.transform.Source;
27 import javax.xml.transform.stream.StreamSource;
28
29 import org.argeo.api.acr.Content;
30 import org.argeo.api.acr.ContentUtils;
31 import org.argeo.api.acr.NamespaceUtils;
32 import org.argeo.api.acr.spi.AbstractContent;
33 import org.argeo.api.acr.spi.ProvidedSession;
34 import org.argeo.jcr.Jcr;
35 import org.argeo.jcr.JcrException;
36 import org.argeo.jcr.JcrUtils;
37
38 /** A JCR {@link Node} accessed as {@link Content}. */
39 public class JcrContent extends AbstractContent {
40 // private Node jcrNode;
41
42 private JcrContentProvider provider;
43 private ProvidedSession session;
44
45 private String jcrWorkspace;
46 private String jcrPath;
47
48 protected JcrContent(ProvidedSession session, JcrContentProvider provider, String jcrWorkspace, String jcrPath) {
49 this.session = session;
50 this.provider = provider;
51 this.jcrWorkspace = jcrWorkspace;
52 this.jcrPath = jcrPath;
53 }
54
55 @Override
56 public QName getName() {
57 String name = Jcr.getName(getJcrNode());
58 if (name.equals("")) {// root
59 String mountPath = provider.getMountPath();
60 name = ContentUtils.getParentPath(mountPath)[1];
61 // name = Jcr.getWorkspaceName(getJcrNode());
62 }
63 return NamespaceUtils.parsePrefixedName(provider, name);
64 }
65
66 @SuppressWarnings("unchecked")
67 @Override
68 public <A> Optional<A> get(QName key, Class<A> clss) {
69 if (isDefaultAttrTypeRequested(clss)) {
70 return Optional.of((A) get(getJcrNode(), key.toString()));
71 }
72 return Optional.of((A) Jcr.get(getJcrNode(), key.toString()));
73 }
74
75 @Override
76 public Iterator<Content> iterator() {
77 try {
78 return new JcrContentIterator(getJcrNode().getNodes());
79 } catch (RepositoryException e) {
80 throw new JcrException("Cannot list children of " + getJcrNode(), e);
81 }
82 }
83
84 @Override
85 protected Iterable<QName> keys() {
86 try {
87 Set<QName> keys = new HashSet<>();
88 for (PropertyIterator propertyIterator = getJcrNode().getProperties(); propertyIterator.hasNext();) {
89 Property property = propertyIterator.nextProperty();
90 // TODO convert standard names
91 // TODO skip technical properties
92 QName name = NamespaceUtils.parsePrefixedName(provider, property.getName());
93 keys.add(name);
94 }
95 return keys;
96 } catch (RepositoryException e) {
97 throw new JcrException("Cannot list properties of " + getJcrNode(), e);
98 }
99 }
100
101 public Node getJcrNode() {
102 try {
103 // TODO caching?
104 return provider.getJcrSession(session, jcrWorkspace).getNode(jcrPath);
105 } catch (RepositoryException e) {
106 throw new JcrException("Cannot retrieve " + jcrPath + " from workspace " + jcrWorkspace, e);
107 }
108 }
109
110 /** Cast to a standard Java object. */
111 static Object get(Node node, String property) {
112 try {
113 Property p = node.getProperty(property);
114 if (p.isMultiple()) {
115 Value[] values = p.getValues();
116 List<Object> lst = new ArrayList<>();
117 for (Value value : values) {
118 lst.add(convertSingleValue(value));
119 }
120 return lst;
121 } else {
122 Value value = node.getProperty(property).getValue();
123 return convertSingleValue(value);
124 }
125 } catch (RepositoryException e) {
126 throw new JcrException("Cannot cast value from " + property + " of node " + node, e);
127 }
128 }
129
130 static Object convertSingleValue(Value value) throws RepositoryException {
131 switch (value.getType()) {
132 case PropertyType.STRING:
133 return value.getString();
134 case PropertyType.DOUBLE:
135 return (Double) value.getDouble();
136 case PropertyType.LONG:
137 return (Long) value.getLong();
138 case PropertyType.BOOLEAN:
139 return (Boolean) value.getBoolean();
140 case PropertyType.DATE:
141 Calendar calendar = value.getDate();
142 return calendar.toInstant();
143 case PropertyType.BINARY:
144 throw new IllegalArgumentException("Binary is not supported as an attribute");
145 default:
146 return value.getString();
147 }
148 }
149
150 class JcrContentIterator implements Iterator<Content> {
151 private final NodeIterator nodeIterator;
152 // we keep track in order to be able to delete it
153 private JcrContent current = null;
154
155 protected JcrContentIterator(NodeIterator nodeIterator) {
156 this.nodeIterator = nodeIterator;
157 }
158
159 @Override
160 public boolean hasNext() {
161 return nodeIterator.hasNext();
162 }
163
164 @Override
165 public Content next() {
166 current = new JcrContent(session, provider, jcrWorkspace, Jcr.getPath(nodeIterator.nextNode()));
167 return current;
168 }
169
170 @Override
171 public void remove() {
172 if (current != null) {
173 Jcr.remove(current.getJcrNode());
174 }
175 }
176
177 }
178
179 @Override
180 public Content getParent() {
181 return new JcrContent(session, provider, jcrWorkspace, Jcr.getParentPath(getJcrNode()));
182 }
183
184 @Override
185 public Content add(QName name, QName... classes) {
186 if (classes.length > 0) {
187 QName primaryType = classes[0];
188 Node child = Jcr.addNode(getJcrNode(), name.toString(), primaryType.toString());
189 for (int i = 1; i < classes.length; i++) {
190 try {
191 child.addMixin(classes[i].toString());
192 } catch (RepositoryException e) {
193 throw new JcrException("Cannot add child to " + getJcrNode(), e);
194 }
195 }
196
197 } else {
198 Jcr.addNode(getJcrNode(), name.toString(), NodeType.NT_UNSTRUCTURED);
199 }
200 return null;
201 }
202
203 @Override
204 public void remove() {
205 Jcr.remove(getJcrNode());
206 }
207
208 @Override
209 protected void removeAttr(QName key) {
210 Property property = Jcr.getProperty(getJcrNode(), key.toString());
211 if (property != null) {
212 try {
213 property.remove();
214 } catch (RepositoryException e) {
215 throw new JcrException("Cannot remove property " + key + " from " + getJcrNode(), e);
216 }
217 }
218
219 }
220
221 /*
222 * ADAPTERS
223 */
224 public <A> A adapt(Class<A> clss) {
225 if (Source.class.isAssignableFrom(clss)) {
226 // try {
227 PipedInputStream in = new PipedInputStream();
228
229 ForkJoinPool.commonPool().execute(() -> {
230 try (PipedOutputStream out = new PipedOutputStream(in)) {
231 provider.getJcrSession(session, jcrWorkspace).exportDocumentView(jcrPath, out, true, false);
232 out.flush();
233 } catch (IOException | RepositoryException e) {
234 throw new RuntimeException("Cannot export " + jcrPath + " in workspace " + jcrWorkspace, e);
235 }
236
237 });
238 return (A) new StreamSource(in);
239 // } catch (IOException e) {
240 // throw new RuntimeException("Cannot adapt " + JcrContent.this + " to " + clss, e);
241 // }
242 } else
243
244 return super.adapt(clss);
245 }
246
247 @Override
248 public <C extends Closeable> C open(Class<C> clss) throws IOException, IllegalArgumentException {
249 if (InputStream.class.isAssignableFrom(clss)) {
250 Node node = getJcrNode();
251 if (Jcr.isNodeType(node, NodeType.NT_FILE)) {
252 try {
253 return (C) JcrUtils.getFileAsStream(node);
254 } catch (RepositoryException e) {
255 throw new JcrException("Cannot open " + jcrPath + " in workspace " + jcrWorkspace, e);
256 }
257 }
258 }
259 return super.open(clss);
260 }
261
262 // class JcrKeyIterator implements Iterator<QName> {
263 // private final PropertyIterator propertyIterator;
264 //
265 // protected JcrKeyIterator(PropertyIterator propertyIterator) {
266 // this.propertyIterator = propertyIterator;
267 // }
268 //
269 // @Override
270 // public boolean hasNext() {
271 // return propertyIterator.hasNext();
272 // }
273 //
274 // @Override
275 // public QName next() {
276 // Property property = null;
277 // try {
278 // property = propertyIterator.nextProperty();
279 // // TODO map standard property names
280 // return NamespaceUtils.parsePrefixedName(provider, property.getName());
281 // } catch (RepositoryException e) {
282 // throw new JcrException("Cannot retrieve property " + property, null);
283 // }
284 // }
285 //
286 // }
287 }