1 package org
.argeo
.cms
.jcr
.acr
;
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
;
15 import java
.util
.concurrent
.ForkJoinPool
;
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
;
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
;
38 /** A JCR {@link Node} accessed as {@link Content}. */
39 public class JcrContent
extends AbstractContent
{
40 // private Node jcrNode;
42 private JcrContentProvider provider
;
43 private ProvidedSession session
;
45 private String jcrWorkspace
;
46 private String jcrPath
;
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
;
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());
63 return NamespaceUtils
.parsePrefixedName(provider
, name
);
66 @SuppressWarnings("unchecked")
68 public <A
> Optional
<A
> get(QName key
, Class
<A
> clss
) {
69 if (isDefaultAttrTypeRequested(clss
)) {
70 return Optional
.of((A
) get(getJcrNode(), key
.toString()));
72 return Optional
.of((A
) Jcr
.get(getJcrNode(), key
.toString()));
76 public Iterator
<Content
> iterator() {
78 return new JcrContentIterator(getJcrNode().getNodes());
79 } catch (RepositoryException e
) {
80 throw new JcrException("Cannot list children of " + getJcrNode(), e
);
85 protected Iterable
<QName
> keys() {
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());
96 } catch (RepositoryException e
) {
97 throw new JcrException("Cannot list properties of " + getJcrNode(), e
);
101 public Node
getJcrNode() {
104 return provider
.getJcrSession(session
, jcrWorkspace
).getNode(jcrPath
);
105 } catch (RepositoryException e
) {
106 throw new JcrException("Cannot retrieve " + jcrPath
+ " from workspace " + jcrWorkspace
, e
);
110 /** Cast to a standard Java object. */
111 static Object
get(Node node
, String property
) {
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
));
122 Value value
= node
.getProperty(property
).getValue();
123 return convertSingleValue(value
);
125 } catch (RepositoryException e
) {
126 throw new JcrException("Cannot cast value from " + property
+ " of node " + node
, e
);
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");
146 return value
.getString();
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;
155 protected JcrContentIterator(NodeIterator nodeIterator
) {
156 this.nodeIterator
= nodeIterator
;
160 public boolean hasNext() {
161 return nodeIterator
.hasNext();
165 public Content
next() {
166 current
= new JcrContent(session
, provider
, jcrWorkspace
, Jcr
.getPath(nodeIterator
.nextNode()));
171 public void remove() {
172 if (current
!= null) {
173 Jcr
.remove(current
.getJcrNode());
180 public Content
getParent() {
181 return new JcrContent(session
, provider
, jcrWorkspace
, Jcr
.getParentPath(getJcrNode()));
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
++) {
191 child
.addMixin(classes
[i
].toString());
192 } catch (RepositoryException e
) {
193 throw new JcrException("Cannot add child to " + getJcrNode(), e
);
198 Jcr
.addNode(getJcrNode(), name
.toString(), NodeType
.NT_UNSTRUCTURED
);
204 public void remove() {
205 Jcr
.remove(getJcrNode());
209 protected void removeAttr(QName key
) {
210 Property property
= Jcr
.getProperty(getJcrNode(), key
.toString());
211 if (property
!= null) {
214 } catch (RepositoryException e
) {
215 throw new JcrException("Cannot remove property " + key
+ " from " + getJcrNode(), e
);
224 public <A
> A
adapt(Class
<A
> clss
) {
225 if (Source
.class.isAssignableFrom(clss
)) {
227 PipedInputStream in
= new PipedInputStream();
229 ForkJoinPool
.commonPool().execute(() -> {
230 try (PipedOutputStream out
= new PipedOutputStream(in
)) {
231 provider
.getJcrSession(session
, jcrWorkspace
).exportDocumentView(jcrPath
, out
, true, false);
233 } catch (IOException
| RepositoryException e
) {
234 throw new RuntimeException("Cannot export " + jcrPath
+ " in workspace " + jcrWorkspace
, e
);
238 return (A
) new StreamSource(in
);
239 // } catch (IOException e) {
240 // throw new RuntimeException("Cannot adapt " + JcrContent.this + " to " + clss, e);
244 return super.adapt(clss
);
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
)) {
253 return (C
) JcrUtils
.getFileAsStream(node
);
254 } catch (RepositoryException e
) {
255 throw new JcrException("Cannot open " + jcrPath
+ " in workspace " + jcrWorkspace
, e
);
259 return super.open(clss
);
262 // class JcrKeyIterator implements Iterator<QName> {
263 // private final PropertyIterator propertyIterator;
265 // protected JcrKeyIterator(PropertyIterator propertyIterator) {
266 // this.propertyIterator = propertyIterator;
270 // public boolean hasNext() {
271 // return propertyIterator.hasNext();
275 // public QName next() {
276 // Property property = null;
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);