3 import java
.io
.ByteArrayOutputStream
;
4 import java
.io
.IOException
;
5 import java
.io
.InputStream
;
6 import java
.math
.BigDecimal
;
7 import java
.text
.MessageFormat
;
8 import java
.time
.Instant
;
9 import java
.util
.ArrayList
;
10 import java
.util
.Arrays
;
11 import java
.util
.Calendar
;
12 import java
.util
.Collections
;
13 import java
.util
.Date
;
14 import java
.util
.GregorianCalendar
;
15 import java
.util
.Iterator
;
16 import java
.util
.List
;
18 import javax
.jcr
.Binary
;
19 import javax
.jcr
.ItemNotFoundException
;
20 import javax
.jcr
.Node
;
21 import javax
.jcr
.NodeIterator
;
22 import javax
.jcr
.Property
;
23 import javax
.jcr
.PropertyType
;
24 import javax
.jcr
.Repository
;
25 import javax
.jcr
.RepositoryException
;
26 import javax
.jcr
.Session
;
27 import javax
.jcr
.Value
;
28 import javax
.jcr
.Workspace
;
29 import javax
.jcr
.nodetype
.NodeType
;
30 import javax
.jcr
.query
.Query
;
31 import javax
.jcr
.query
.QueryManager
;
32 import javax
.jcr
.query
.Row
;
33 import javax
.jcr
.security
.Privilege
;
34 import javax
.jcr
.version
.Version
;
35 import javax
.jcr
.version
.VersionHistory
;
36 import javax
.jcr
.version
.VersionIterator
;
37 import javax
.jcr
.version
.VersionManager
;
39 import org
.apache
.commons
.io
.IOUtils
;
42 * Utility class whose purpose is to make using JCR less verbose by
43 * systematically using unchecked exceptions and returning <code>null</code>
44 * when something is not found. This is especially useful when writing user
45 * interfaces (such as with SWT) where listeners and callbacks expect unchecked
46 * exceptions. Loosely inspired by Java's <code>Files</code> singleton.
50 * The name of a node which will be serialized as XML text, as per section 7.3.1
51 * of the JCR 2.0 specifications.
53 public final static String JCR_XMLTEXT
= "jcr:xmltext";
55 * The name of a property which will be serialized as XML text, as per section
56 * 7.3.1 of the JCR 2.0 specifications.
58 public final static String JCR_XMLCHARACTERS
= "jcr:xmlcharacters";
60 * <code>jcr:name</code>, when used in another context than
61 * {@link Property#JCR_NAME}, typically to name a node rather than a property.
63 public final static String JCR_NAME
= "jcr:name";
65 * <code>jcr:path</code>, when used in another context than
66 * {@link Property#JCR_PATH}, typically to name a node rather than a property.
68 public final static String JCR_PATH
= "jcr:path";
70 * <code>jcr:primaryType</code> with prefix instead of namespace (as in
71 * {@link Property#JCR_PRIMARY_TYPE}.
73 public final static String JCR_PRIMARY_TYPE
= "jcr:primaryType";
75 * <code>jcr:mixinTypes</code> with prefix instead of namespace (as in
76 * {@link Property#JCR_MIXIN_TYPES}.
78 public final static String JCR_MIXIN_TYPES
= "jcr:mixinTypes";
80 * <code>jcr:uuid</code> with prefix instead of namespace (as in
81 * {@link Property#JCR_UUID}.
83 public final static String JCR_UUID
= "jcr:uuid";
85 * <code>jcr:created</code> with prefix instead of namespace (as in
86 * {@link Property#JCR_CREATED}.
88 public final static String JCR_CREATED
= "jcr:created";
90 * <code>jcr:createdBy</code> with prefix instead of namespace (as in
91 * {@link Property#JCR_CREATED_BY}.
93 public final static String JCR_CREATED_BY
= "jcr:createdBy";
95 * <code>jcr:lastModified</code> with prefix instead of namespace (as in
96 * {@link Property#JCR_LAST_MODIFIED}.
98 public final static String JCR_LAST_MODIFIED
= "jcr:lastModified";
100 * <code>jcr:lastModifiedBy</code> with prefix instead of namespace (as in
101 * {@link Property#JCR_LAST_MODIFIED_BY}.
103 public final static String JCR_LAST_MODIFIED_BY
= "jcr:lastModifiedBy";
106 * @see Node#isNodeType(String)
107 * @throws JcrException caused by {@link RepositoryException}
109 public static boolean isNodeType(Node node
, String nodeTypeName
) {
111 return node
.isNodeType(nodeTypeName
);
112 } catch (RepositoryException e
) {
113 throw new JcrException("Cannot get whether " + node
+ " is of type " + nodeTypeName
, e
);
118 * @see Node#hasNodes()
119 * @throws JcrException caused by {@link RepositoryException}
121 public static boolean hasNodes(Node node
) {
123 return node
.hasNodes();
124 } catch (RepositoryException e
) {
125 throw new JcrException("Cannot get whether " + node
+ " has children.", e
);
130 * @see Node#getParent()
131 * @throws JcrException caused by {@link RepositoryException}
133 public static Node
getParent(Node node
) {
135 return isRoot(node
) ?
null : node
.getParent();
136 } catch (RepositoryException e
) {
137 throw new JcrException("Cannot get parent of " + node
, e
);
142 * @see Node#getParent()
143 * @throws JcrException caused by {@link RepositoryException}
145 public static String
getParentPath(Node node
) {
146 return getPath(getParent(node
));
150 * Whether this node is the root node.
152 * @throws JcrException caused by {@link RepositoryException}
154 public static boolean isRoot(Node node
) {
156 return node
.getDepth() == 0;
157 } catch (RepositoryException e
) {
158 throw new JcrException("Cannot get depth of " + node
, e
);
163 * @see Node#getPath()
164 * @throws JcrException caused by {@link RepositoryException}
166 public static String
getPath(Node node
) {
168 return node
.getPath();
169 } catch (RepositoryException e
) {
170 throw new JcrException("Cannot get path of " + node
, e
);
175 * @see Node#getSession()
176 * @see Session#getWorkspace()
177 * @see Workspace#getName()
179 public static String
getWorkspaceName(Node node
) {
180 return session(node
).getWorkspace().getName();
184 * @see Node#getIdentifier()
185 * @throws JcrException caused by {@link RepositoryException}
187 public static String
getIdentifier(Node node
) {
189 return node
.getIdentifier();
190 } catch (RepositoryException e
) {
191 throw new JcrException("Cannot get identifier of " + node
, e
);
196 * @see Node#getName()
197 * @throws JcrException caused by {@link RepositoryException}
199 public static String
getName(Node node
) {
201 return node
.getName();
202 } catch (RepositoryException e
) {
203 throw new JcrException("Cannot get name of " + node
, e
);
208 * Returns the node name with its current index (useful for re-ordering).
210 * @see Node#getName()
211 * @see Node#getIndex()
212 * @throws JcrException caused by {@link RepositoryException}
214 public static String
getIndexedName(Node node
) {
216 return node
.getName() + "[" + node
.getIndex() + "]";
217 } catch (RepositoryException e
) {
218 throw new JcrException("Cannot get name of " + node
, e
);
223 * @see Node#getProperty(String)
224 * @throws JcrException caused by {@link RepositoryException}
226 public static Property
getProperty(Node node
, String property
) {
228 if (node
.hasProperty(property
))
229 return node
.getProperty(property
);
232 } catch (RepositoryException e
) {
233 throw new JcrException("Cannot get property " + property
+ " of " + node
, e
);
238 * @see Node#getIndex()
239 * @throws JcrException caused by {@link RepositoryException}
241 public static int getIndex(Node node
) {
243 return node
.getIndex();
244 } catch (RepositoryException e
) {
245 throw new JcrException("Cannot get index of " + node
, e
);
250 * If node has mixin {@link NodeType#MIX_TITLE}, return
251 * {@link Property#JCR_TITLE}, otherwise return {@link #getName(Node)}.
253 public static String
getTitle(Node node
) {
254 if (Jcr
.isNodeType(node
, NodeType
.MIX_TITLE
))
255 return get(node
, Property
.JCR_TITLE
);
257 return Jcr
.getName(node
);
260 /** Accesses a {@link NodeIterator} as an {@link Iterable}. */
261 @SuppressWarnings("unchecked")
262 public static Iterable
<Node
> iterate(NodeIterator nodeIterator
) {
263 return new Iterable
<Node
>() {
266 public Iterator
<Node
> iterator() {
273 * @return the children as an {@link Iterable} for use in for-each llops.
274 * @see Node#getNodes()
275 * @throws JcrException caused by {@link RepositoryException}
277 public static Iterable
<Node
> nodes(Node node
) {
279 return iterate(node
.getNodes());
280 } catch (RepositoryException e
) {
281 throw new JcrException("Cannot get children of " + node
, e
);
286 * @return the children as a (possibly empty) {@link List}.
287 * @see Node#getNodes()
288 * @throws JcrException caused by {@link RepositoryException}
290 public static List
<Node
> getNodes(Node node
) {
291 List
<Node
> nodes
= new ArrayList
<>();
293 if (node
.hasNodes()) {
294 NodeIterator nit
= node
.getNodes();
295 while (nit
.hasNext())
296 nodes
.add(nit
.nextNode());
300 } catch (RepositoryException e
) {
301 throw new JcrException("Cannot get children of " + node
, e
);
306 * @return the child or <code>null</node> if not found
307 * @see Node#getNode(String)
308 * @throws JcrException caused by {@link RepositoryException}
310 public static Node
getNode(Node node
, String child
) {
312 if (node
.hasNode(child
))
313 return node
.getNode(child
);
316 } catch (RepositoryException e
) {
317 throw new JcrException("Cannot get child of " + node
, e
);
322 * @return the node at this path or <code>null</node> if not found
323 * @see Session#getNode(String)
324 * @throws JcrException caused by {@link RepositoryException}
326 public static Node
getNode(Session session
, String path
) {
328 if (session
.nodeExists(path
))
329 return session
.getNode(path
);
332 } catch (RepositoryException e
) {
333 throw new JcrException("Cannot get node " + path
, e
);
338 * Add a node to this parent, setting its primary type and its mixins.
340 * @param parent the parent node
341 * @param name the name of the node, if <code>null</code>, the primary
342 * type will be used (typically for XML structures)
343 * @param primaryType the primary type, if <code>null</code>
344 * {@link NodeType#NT_UNSTRUCTURED} will be used.
345 * @param mixins the mixins
346 * @return the created node
347 * @see Node#addNode(String, String)
348 * @see Node#addMixin(String)
350 public static Node
addNode(Node parent
, String name
, String primaryType
, String
... mixins
) {
351 if (name
== null && primaryType
== null)
352 throw new IllegalArgumentException("Both node name and primary type cannot be null");
354 Node newNode
= parent
.addNode(name
== null ? primaryType
: name
,
355 primaryType
== null ? NodeType
.NT_UNSTRUCTURED
: primaryType
);
356 for (String mixin
: mixins
) {
357 newNode
.addMixin(mixin
);
360 } catch (RepositoryException e
) {
361 throw new JcrException("Cannot add node " + name
+ " to " + parent
, e
);
366 * Add an {@link NodeType#NT_BASE} node to this parent.
368 * @param parent the parent node
369 * @param name the name of the node, cannot be <code>null</code>
370 * @return the created node
372 * @see Node#addNode(String)
374 public static Node
addNode(Node parent
, String name
) {
376 throw new IllegalArgumentException("Node name cannot be null");
378 Node newNode
= parent
.addNode(name
);
380 } catch (RepositoryException e
) {
381 throw new JcrException("Cannot add node " + name
+ " to " + parent
, e
);
386 * Add mixins to a node.
388 * @param node the node
389 * @param mixins the mixins
390 * @see Node#addMixin(String)
392 public static void addMixin(Node node
, String
... mixins
) {
394 for (String mixin
: mixins
) {
395 node
.addMixin(mixin
);
397 } catch (RepositoryException e
) {
398 throw new JcrException("Cannot add mixins " + Arrays
.asList(mixins
) + " to " + node
, e
);
407 public static void remove(Node node
) {
410 } catch (RepositoryException e
) {
411 throw new JcrException("Cannot remove node " + node
, e
);
416 * @return the node with htis id or <code>null</node> if not found
417 * @see Session#getNodeByIdentifier(String)
418 * @throws JcrException caused by {@link RepositoryException}
420 public static Node
getNodeById(Session session
, String id
) {
422 return session
.getNodeByIdentifier(id
);
423 } catch (ItemNotFoundException e
) {
425 } catch (RepositoryException e
) {
426 throw new JcrException("Cannot get node with id " + id
, e
);
431 * Set a property to the given value, or remove it if the value is
434 * @throws JcrException caused by {@link RepositoryException}
436 public static void set(Node node
, String property
, Object value
) {
438 if (!node
.hasProperty(property
)) {
440 if (value
instanceof List
) {// multiple
441 List
<?
> lst
= (List
<?
>) value
;
442 String
[] values
= new String
[lst
.size()];
443 for (int i
= 0; i
< lst
.size(); i
++) {
444 values
[i
] = lst
.get(i
).toString();
446 node
.setProperty(property
, values
);
448 node
.setProperty(property
, value
.toString());
453 Property prop
= node
.getProperty(property
);
460 if (value
instanceof List
) {
461 List
<?
> lst
= (List
<?
>) value
;
462 String
[] values
= new String
[lst
.size()];
464 for (int i
= 0; i
< lst
.size(); i
++) {
465 values
[i
] = lst
.get(i
).toString();
467 if (!prop
.isMultiple())
469 node
.setProperty(property
, values
);
474 if (prop
.isMultiple()) {
476 node
.setProperty(property
, value
.toString());
480 if (value
instanceof String
)
481 prop
.setValue((String
) value
);
482 else if (value
instanceof Long
)
483 prop
.setValue((Long
) value
);
484 else if (value
instanceof Integer
)
485 prop
.setValue(((Integer
) value
).longValue());
486 else if (value
instanceof Double
)
487 prop
.setValue((Double
) value
);
488 else if (value
instanceof Float
)
489 prop
.setValue(((Float
) value
).doubleValue());
490 else if (value
instanceof Calendar
)
491 prop
.setValue((Calendar
) value
);
492 else if (value
instanceof BigDecimal
)
493 prop
.setValue((BigDecimal
) value
);
494 else if (value
instanceof Boolean
)
495 prop
.setValue((Boolean
) value
);
496 else if (value
instanceof byte[])
497 JcrUtils
.setBinaryAsBytes(prop
, (byte[]) value
);
498 else if (value
instanceof Instant
) {
499 Instant instant
= (Instant
) value
;
500 GregorianCalendar calendar
= new GregorianCalendar();
501 calendar
.setTime(Date
.from(instant
));
502 prop
.setValue(calendar
);
503 } else // try with toString()
504 prop
.setValue(value
.toString());
505 } catch (RepositoryException e
) {
506 throw new JcrException("Cannot set property " + property
+ " of " + node
+ " to " + value
, e
);
511 * Get property as {@link String}.
513 * @return the value of
514 * {@link Node#getProperty(String)}.{@link Property#getString()} or
515 * <code>null</code> if the property does not exist.
516 * @throws JcrException caused by {@link RepositoryException}
518 public static String
get(Node node
, String property
) {
519 return get(node
, property
, null);
523 * Get property as a {@link String}. If the property is multiple it returns the
526 * @return the value of
527 * {@link Node#getProperty(String)}.{@link Property#getString()} or
528 * <code>defaultValue</code> if the property does not exist.
529 * @throws JcrException caused by {@link RepositoryException}
531 public static String
get(Node node
, String property
, String defaultValue
) {
533 if (node
.hasProperty(property
)) {
534 Property p
= node
.getProperty(property
);
536 return p
.getString();
538 Value
[] values
= p
.getValues();
539 if (values
.length
== 0)
542 return values
[0].getString();
546 } catch (RepositoryException e
) {
547 throw new JcrException("Cannot retrieve property " + property
+ " from " + node
, e
);
552 * Get property as a {@link Value}.
554 * @return {@link Node#getProperty(String)} or <code>null</code> if the property
556 * @throws JcrException caused by {@link RepositoryException}
558 public static Value
getValue(Node node
, String property
) {
560 if (node
.hasProperty(property
))
561 return node
.getProperty(property
).getValue();
564 } catch (RepositoryException e
) {
565 throw new JcrException("Cannot retrieve property " + property
+ " from " + node
, e
);
570 * Get property doing a best effort to cast it as the target object.
572 * @return the value of {@link Node#getProperty(String)} or
573 * <code>defaultValue</code> if the property does not exist.
574 * @throws IllegalArgumentException if the value could not be cast
575 * @throws JcrException in case of unexpected
576 * {@link RepositoryException}
578 @SuppressWarnings("unchecked")
579 public static <T
> T
getAs(Node node
, String property
, T defaultValue
) {
581 // TODO deal with multiple
582 if (node
.hasProperty(property
)) {
583 Property p
= node
.getProperty(property
);
585 if (p
.isMultiple()) {
586 throw new UnsupportedOperationException("Multiple values properties are not supported");
588 Value value
= p
.getValue();
589 return (T
) get(value
);
590 } catch (ClassCastException e
) {
591 throw new IllegalArgumentException(
592 "Cannot cast property of type " + PropertyType
.nameFromValue(p
.getType()), e
);
597 } catch (RepositoryException e
) {
598 throw new JcrException("Cannot retrieve property " + property
+ " from " + node
, e
);
602 public static <T
> T
getAs(Node node
, String property
, Class
<T
> clss
) {
603 if (String
.class.isAssignableFrom(clss
)) {
604 return (T
) get(node
, property
);
605 } else if (Long
.class.isAssignableFrom(clss
)) {
606 return (T
) get(node
, property
);
608 throw new IllegalArgumentException("Unsupported format " + clss
);
613 * Retrieve a {@link PropertyType#DATE} property as an {@link Instant}.
615 * @return the property value, or <code>null</code> if not found.
617 public static Instant
getAsInstant(Node node
, String property
) {
619 if (!node
.hasProperty(property
))
621 Calendar calendar
= node
.getProperty(property
).getDate();
622 return calendar
.getTime().toInstant();
623 } catch (RepositoryException e
) {
624 throw new JcrException("Cannot get property " + property
+ " of " + node
+ " as an instant.", e
);
630 * Get a multiple property as a list, doing a best effort to cast it as the
633 * @return the value of {@link Node#getProperty(String)}.
634 * @throws IllegalArgumentException if the value could not be cast
635 * @throws JcrException in case of unexpected
636 * {@link RepositoryException}
638 public static <T
> List
<T
> getMultiple(Node node
, String property
) {
640 if (node
.hasProperty(property
)) {
641 Property p
= node
.getProperty(property
);
642 return getMultiple(p
);
646 } catch (RepositoryException e
) {
647 throw new JcrException("Cannot retrieve multiple values property " + property
+ " from " + node
, e
);
652 * Get a multiple property as a list, doing a best effort to cast it as the
655 @SuppressWarnings("unchecked")
656 public static <T
> List
<T
> getMultiple(Property p
) {
658 List
<T
> res
= new ArrayList
<>();
659 if (!p
.isMultiple()) {
660 res
.add((T
) get(p
.getValue()));
663 Value
[] values
= p
.getValues();
664 for (Value value
: values
) {
665 res
.add((T
) get(value
));
668 } catch (ClassCastException
| RepositoryException e
) {
669 throw new IllegalArgumentException("Cannot get property " + p
, e
);
673 /** Cast a {@link Value} to a standard Java object. */
674 public static Object
get(Value value
) {
675 Binary binary
= null;
677 switch (value
.getType()) {
678 case PropertyType
.STRING
:
679 return value
.getString();
680 case PropertyType
.DOUBLE
:
681 return (Double
) value
.getDouble();
682 case PropertyType
.LONG
:
683 return (Long
) value
.getLong();
684 case PropertyType
.BOOLEAN
:
685 return (Boolean
) value
.getBoolean();
686 case PropertyType
.DATE
:
687 return value
.getDate();
688 case PropertyType
.BINARY
:
689 binary
= value
.getBinary();
691 try (InputStream in
= binary
.getStream(); ByteArrayOutputStream out
= new ByteArrayOutputStream();) {
692 IOUtils
.copy(in
, out
);
693 arr
= out
.toByteArray();
694 } catch (IOException e
) {
695 throw new RuntimeException("Cannot read binary from " + value
, e
);
699 return value
.getString();
701 } catch (RepositoryException e
) {
702 throw new JcrException("Cannot cast value from " + value
, e
);
710 * Retrieves the {@link Session} related to this node.
712 * @deprecated Use {@link #getSession(Node)} instead.
715 public static Session
session(Node node
) {
716 return getSession(node
);
719 /** Retrieves the {@link Session} related to this node. */
720 public static Session
getSession(Node node
) {
722 return node
.getSession();
723 } catch (RepositoryException e
) {
724 throw new JcrException("Cannot retrieve session related to " + node
, e
);
728 /** Retrieves the root node related to this session. */
729 public static Node
getRootNode(Session session
) {
731 return session
.getRootNode();
732 } catch (RepositoryException e
) {
733 throw new JcrException("Cannot get root node for " + session
, e
);
737 /** Whether this item exists. */
738 public static boolean itemExists(Session session
, String path
) {
740 return session
.itemExists(path
);
741 } catch (RepositoryException e
) {
742 throw new JcrException("Cannot check whether " + path
+ " exists", e
);
747 * Saves the {@link Session} related to this node. Note that all other unrelated
748 * modifications in this session will also be saved.
750 public static void save(Node node
) {
752 Session session
= node
.getSession();
753 // if (node.isNodeType(NodeType.MIX_LAST_MODIFIED)) {
754 // set(node, Property.JCR_LAST_MODIFIED, Instant.now());
755 // set(node, Property.JCR_LAST_MODIFIED_BY, session.getUserID());
757 if (session
.hasPendingChanges())
759 } catch (RepositoryException e
) {
760 throw new JcrException("Cannot save session related to " + node
+ " in workspace "
761 + session(node
).getWorkspace().getName(), e
);
765 /** Login to a JCR repository. */
766 public static Session
login(Repository repository
, String workspace
) {
768 return repository
.login(workspace
);
769 } catch (RepositoryException e
) {
770 throw new IllegalArgumentException("Cannot login to repository", e
);
774 /** Safely and silently logs out a session. */
775 public static void logout(Session session
) {
778 if (session
.isLive())
780 } catch (Exception e
) {
785 /** Safely and silently logs out the underlying session. */
786 public static void logout(Node node
) {
787 Jcr
.logout(session(node
));
794 * Add a single privilege to a node.
798 public static void addPrivilege(Node node
, String principal
, String privilege
) {
800 Session session
= node
.getSession();
801 JcrUtils
.addPrivilege(session
, node
.getPath(), principal
, privilege
);
802 } catch (RepositoryException e
) {
803 throw new JcrException("Cannot add privilege " + privilege
+ " to " + node
, e
);
810 /** Get checked out status. */
811 public static boolean isCheckedOut(Node node
) {
813 return node
.isCheckedOut();
814 } catch (RepositoryException e
) {
815 throw new JcrException("Cannot retrieve checked out status of " + node
, e
);
819 /** @see VersionManager#checkpoint(String) */
820 public static void checkpoint(Node node
) {
822 versionManager(node
).checkpoint(node
.getPath());
823 } catch (RepositoryException e
) {
824 throw new JcrException("Cannot check in " + node
, e
);
828 /** @see VersionManager#checkin(String) */
829 public static void checkin(Node node
) {
831 versionManager(node
).checkin(node
.getPath());
832 } catch (RepositoryException e
) {
833 throw new JcrException("Cannot check in " + node
, e
);
837 /** @see VersionManager#checkout(String) */
838 public static void checkout(Node node
) {
840 versionManager(node
).checkout(node
.getPath());
841 } catch (RepositoryException e
) {
842 throw new JcrException("Cannot check out " + node
, e
);
846 /** Get the {@link VersionManager} related to this node. */
847 public static VersionManager
versionManager(Node node
) {
849 return node
.getSession().getWorkspace().getVersionManager();
850 } catch (RepositoryException e
) {
851 throw new JcrException("Cannot get version manager from " + node
, e
);
855 /** Get the {@link VersionHistory} related to this node. */
856 public static VersionHistory
getVersionHistory(Node node
) {
858 return versionManager(node
).getVersionHistory(node
.getPath());
859 } catch (RepositoryException e
) {
860 throw new JcrException("Cannot get version history from " + node
, e
);
865 * The linear versions of this version history in reverse order and without the
868 public static List
<Version
> getLinearVersions(VersionHistory versionHistory
) {
870 List
<Version
> lst
= new ArrayList
<>();
871 VersionIterator vit
= versionHistory
.getAllLinearVersions();
872 while (vit
.hasNext())
873 lst
.add(vit
.nextVersion());
875 Collections
.reverse(lst
);
877 } catch (RepositoryException e
) {
878 throw new JcrException("Cannot get linear versions from " + versionHistory
, e
);
882 /** The frozen node related to this {@link Version}. */
883 public static Node
getFrozenNode(Version version
) {
885 return version
.getFrozenNode();
886 } catch (RepositoryException e
) {
887 throw new JcrException("Cannot get frozen node from " + version
, e
);
891 /** Get the base {@link Version} related to this node. */
892 public static Version
getBaseVersion(Node node
) {
894 return versionManager(node
).getBaseVersion(node
.getPath());
895 } catch (RepositoryException e
) {
896 throw new JcrException("Cannot get base version from " + node
, e
);
904 * Returns the size of this file.
906 * @see NodeType#NT_FILE
908 public static long getFileSize(Node fileNode
) {
910 if (!fileNode
.isNodeType(NodeType
.NT_FILE
))
911 throw new IllegalArgumentException(fileNode
+ " must be a file.");
912 return getBinarySize(fileNode
.getNode(Node
.JCR_CONTENT
).getProperty(Property
.JCR_DATA
).getBinary());
913 } catch (RepositoryException e
) {
914 throw new JcrException("Cannot get file size of " + fileNode
, e
);
918 /** Returns the size of this {@link Binary}. */
919 public static long getBinarySize(Binary binaryArg
) {
921 try (Bin binary
= new Bin(binaryArg
)) {
922 return binary
.getSize();
924 } catch (RepositoryException e
) {
925 throw new JcrException("Cannot get file size of binary " + binaryArg
, e
);
930 /** Creates a JCR-SQL2 query using {@link MessageFormat}. */
931 public static Query
createQuery(QueryManager qm
, String sql
, Object
... args
) {
933 sql
= sql
.replaceAll("'", "''");
934 String query
= MessageFormat
.format(sql
, args
);
936 return qm
.createQuery(query
, Query
.JCR_SQL2
);
937 } catch (RepositoryException e
) {
938 throw new JcrException("Cannot create JCR-SQL2 query from " + query
, e
);
942 /** Executes a JCR-SQL2 query using {@link MessageFormat}. */
943 public static NodeIterator
executeQuery(QueryManager qm
, String sql
, Object
... args
) {
944 Query query
= createQuery(qm
, sql
, args
);
946 return query
.execute().getNodes();
947 } catch (RepositoryException e
) {
948 throw new JcrException("Cannot execute query " + sql
+ " with arguments " + Arrays
.asList(args
), e
);
952 /** Executes a JCR-SQL2 query using {@link MessageFormat}. */
953 public static NodeIterator
executeQuery(Session session
, String sql
, Object
... args
) {
954 QueryManager queryManager
;
956 queryManager
= session
.getWorkspace().getQueryManager();
957 } catch (RepositoryException e
) {
958 throw new JcrException("Cannot get query manager from session " + session
, e
);
960 return executeQuery(queryManager
, sql
, args
);
964 * Executes a JCR-SQL2 query using {@link MessageFormat}, which must return a
965 * single node at most.
967 * @return the node or <code>null</code> if not found.
969 public static Node
getNode(QueryManager qm
, String sql
, Object
... args
) {
970 NodeIterator nit
= executeQuery(qm
, sql
, args
);
972 Node node
= nit
.nextNode();
974 throw new IllegalStateException(
975 "Query " + sql
+ " with arguments " + Arrays
.asList(args
) + " returned more than one node.");
983 * Executes a JCR-SQL2 query using {@link MessageFormat}, which must return a
984 * single node at most.
986 * @return the node or <code>null</code> if not found.
988 public static Node
getNode(Session session
, String sql
, Object
... args
) {
989 QueryManager queryManager
;
991 queryManager
= session
.getWorkspace().getQueryManager();
992 } catch (RepositoryException e
) {
993 throw new JcrException("Cannot get query manager from session " + session
, e
);
995 return getNode(queryManager
, sql
, args
);
998 public static Node
getRowNode(Row row
, String selectorName
) {
1000 return row
.getNode(selectorName
);
1001 } catch (RepositoryException e
) {
1002 throw new JcrException("Cannot get node " + selectorName
+ " from row", e
);