3 import java
.math
.BigDecimal
;
4 import java
.time
.Instant
;
5 import java
.util
.ArrayList
;
6 import java
.util
.Calendar
;
7 import java
.util
.Collections
;
9 import java
.util
.GregorianCalendar
;
10 import java
.util
.Iterator
;
11 import java
.util
.List
;
13 import javax
.jcr
.Binary
;
14 import javax
.jcr
.ItemNotFoundException
;
15 import javax
.jcr
.Node
;
16 import javax
.jcr
.NodeIterator
;
17 import javax
.jcr
.Property
;
18 import javax
.jcr
.PropertyType
;
19 import javax
.jcr
.Repository
;
20 import javax
.jcr
.RepositoryException
;
21 import javax
.jcr
.Session
;
22 import javax
.jcr
.Value
;
23 import javax
.jcr
.nodetype
.NodeType
;
24 import javax
.jcr
.security
.Privilege
;
25 import javax
.jcr
.version
.Version
;
26 import javax
.jcr
.version
.VersionHistory
;
27 import javax
.jcr
.version
.VersionIterator
;
28 import javax
.jcr
.version
.VersionManager
;
31 * Utility class whose purpose is to make using JCR less verbose by
32 * systematically using unchecked exceptions and returning <code>null</code>
33 * when something is not found. This is especially useful when writing user
34 * interfaces (such as with SWT) where listeners and callbacks expect unchecked
35 * exceptions. Loosely inspired by Java's <code>Files</code> singleton.
40 * @see Node#isNodeType(String)
41 * @throws IllegalStateException caused by {@link RepositoryException}
43 public static boolean isNodeType(Node node
, String nodeTypeName
) {
45 return node
.isNodeType(nodeTypeName
);
46 } catch (RepositoryException e
) {
47 throw new IllegalStateException("Cannot get whether " + node
+ " is of type " + nodeTypeName
, e
);
52 * @see Node#hasNodes()
53 * @throws IllegalStateException caused by {@link RepositoryException}
55 public static boolean hasNodes(Node node
) {
57 return node
.hasNodes();
58 } catch (RepositoryException e
) {
59 throw new IllegalStateException("Cannot get whether " + node
+ " has children.", e
);
64 * @see Node#getParent()
65 * @throws IllegalStateException caused by {@link RepositoryException}
67 public static Node
getParent(Node node
) {
69 return isRoot(node
) ?
null : node
.getParent();
70 } catch (RepositoryException e
) {
71 throw new IllegalStateException("Cannot get parent of " + node
, e
);
76 * Whether this node is the root node.
78 * @throws IllegalStateException caused by {@link RepositoryException}
80 public static boolean isRoot(Node node
) {
82 return node
.getDepth() == 0;
83 } catch (RepositoryException e
) {
84 throw new IllegalStateException("Cannot get depth of " + node
, e
);
90 * @throws IllegalStateException caused by {@link RepositoryException}
92 public static String
getPath(Node node
) {
94 return node
.getPath();
95 } catch (RepositoryException e
) {
96 throw new IllegalStateException("Cannot get path of " + node
, e
);
101 * @see Node#getIdentifier()
102 * @throws IllegalStateException caused by {@link RepositoryException}
104 public static String
getIdentifier(Node node
) {
106 return node
.getIdentifier();
107 } catch (RepositoryException e
) {
108 throw new IllegalStateException("Cannot get identifier of " + node
, e
);
113 * @see Node#getName()
114 * @throws IllegalStateException caused by {@link RepositoryException}
116 public static String
getName(Node node
) {
118 return node
.getName();
119 } catch (RepositoryException e
) {
120 throw new IllegalStateException("Cannot get name of " + node
, e
);
124 /** Accesses a {@link NodeIterator} as an {@link Iterable}. */
125 @SuppressWarnings("unchecked")
126 public static Iterable
<Node
> iterate(NodeIterator nodeIterator
) {
127 return new Iterable
<Node
>() {
130 public Iterator
<Node
> iterator() {
137 * @return the children as an {@link Iterable} for use in for-each llops.
138 * @see Node#getNodes()
139 * @throws IllegalStateException caused by {@link RepositoryException}
141 public static Iterable
<Node
> nodes(Node node
) {
143 return iterate(node
.getNodes());
144 } catch (RepositoryException e
) {
145 throw new IllegalStateException("Cannot get children of " + node
, e
);
150 * @return the children as a (possibly empty) {@link List}.
151 * @see Node#getNodes()
152 * @throws IllegalStateException caused by {@link RepositoryException}
154 public static List
<Node
> getNodes(Node node
) {
155 List
<Node
> nodes
= new ArrayList
<>();
157 if (node
.hasNodes()) {
158 NodeIterator nit
= node
.getNodes();
159 while (nit
.hasNext())
160 nodes
.add(nit
.nextNode());
164 } catch (RepositoryException e
) {
165 throw new IllegalStateException("Cannot get children of " + node
, e
);
170 * @return the child or <code>null</node> if not found
171 * @see Node#getNode(String)
172 * @throws IllegalStateException caused by {@link RepositoryException}
174 public static Node
getNode(Node node
, String child
) {
176 if (node
.hasNode(child
))
177 return node
.getNode(child
);
180 } catch (RepositoryException e
) {
181 throw new IllegalStateException("Cannot get child of " + node
, e
);
186 * @return the node at this path or <code>null</node> if not found
187 * @see Session#getNode(String)
188 * @throws IllegalStateException caused by {@link RepositoryException}
190 public static Node
getNode(Session session
, String path
) {
192 if (session
.nodeExists(path
))
193 return session
.getNode(path
);
196 } catch (RepositoryException e
) {
197 throw new IllegalStateException("Cannot get node " + path
, e
);
202 * @return the node with htis id or <code>null</node> if not found
203 * @see Session#getNodeByIdentifier(String)
204 * @throws IllegalStateException caused by {@link RepositoryException}
206 public static Node
getNodeById(Session session
, String id
) {
208 return session
.getNodeByIdentifier(id
);
209 } catch (ItemNotFoundException e
) {
211 } catch (RepositoryException e
) {
212 throw new IllegalStateException("Cannot get node with id " + id
, e
);
217 * Set a property to the given value, or remove it if the value is
220 * @throws IllegalStateException caused by {@link RepositoryException}
222 public static void set(Node node
, String property
, Object value
) {
224 if (!node
.hasProperty(property
))
225 throw new IllegalArgumentException("No property " + property
+ " in " + node
);
226 Property prop
= node
.getProperty(property
);
232 if (value
instanceof String
)
233 prop
.setValue((String
) value
);
234 else if (value
instanceof Long
)
235 prop
.setValue((Long
) value
);
236 else if (value
instanceof Double
)
237 prop
.setValue((Double
) value
);
238 else if (value
instanceof Calendar
)
239 prop
.setValue((Calendar
) value
);
240 else if (value
instanceof BigDecimal
)
241 prop
.setValue((BigDecimal
) value
);
242 else if (value
instanceof Boolean
)
243 prop
.setValue((Boolean
) value
);
244 else if (value
instanceof byte[])
245 JcrUtils
.setBinaryAsBytes(prop
, (byte[]) value
);
246 else if (value
instanceof Instant
) {
247 Instant instant
= (Instant
) value
;
248 GregorianCalendar calendar
= new GregorianCalendar();
249 calendar
.setTime(Date
.from(instant
));
250 prop
.setValue(calendar
);
251 } else // try with toString()
252 prop
.setValue(value
.toString());
253 } catch (RepositoryException e
) {
254 throw new IllegalStateException("Cannot set property " + property
+ " of " + node
+ " to " + value
, e
);
259 * Get property as {@link String}.
261 * @return the value of
262 * {@link Node#getProperty(String)}.{@link Property#getString()} or
263 * <code>null</code> if the property does not exist.
264 * @throws IllegalStateException caused by {@link RepositoryException}
266 public static String
get(Node node
, String property
) {
267 return get(node
, property
, null);
271 * Get property as a {@link String}.
273 * @return the value of
274 * {@link Node#getProperty(String)}.{@link Property#getString()} or
275 * <code>defaultValue</code> if the property does not exist.
276 * @throws IllegalStateException caused by {@link RepositoryException}
278 public static String
get(Node node
, String property
, String defaultValue
) {
280 if (node
.hasProperty(property
))
281 return node
.getProperty(property
).getString();
284 } catch (RepositoryException e
) {
285 throw new IllegalStateException("Cannot retrieve property " + property
+ " from " + node
);
290 * Get property as a {@link Value}.
292 * @return {@link Node#getProperty(String)} or <code>null</code> if the property
294 * @throws IllegalStateException caused by {@link RepositoryException}
296 public static Value
getValue(Node node
, String property
) {
298 if (node
.hasProperty(property
))
299 return node
.getProperty(property
).getValue();
302 } catch (RepositoryException e
) {
303 throw new IllegalStateException("Cannot retrieve property " + property
+ " from " + node
);
308 * Get property doing a best effort to cast it as the target object.
310 * @return the value of {@link Node#getProperty(String)} or
311 * <code>defaultValue</code> if the property does not exist.
312 * @throws IllegalArgumentException if the value could not be cast
313 * @throws IllegalStateException in case of unexpected
314 * {@link RepositoryException}
316 @SuppressWarnings("unchecked")
317 public static <T
> T
getAs(Node node
, String property
, T defaultValue
) {
319 if (node
.hasProperty(property
)) {
320 Property p
= node
.getProperty(property
);
322 switch (p
.getType()) {
323 case PropertyType
.STRING
:
324 return (T
) node
.getProperty(property
).getString();
325 case PropertyType
.DOUBLE
:
326 return (T
) (Double
) node
.getProperty(property
).getDouble();
327 case PropertyType
.LONG
:
328 return (T
) (Long
) node
.getProperty(property
).getLong();
329 case PropertyType
.BOOLEAN
:
330 return (T
) (Boolean
) node
.getProperty(property
).getBoolean();
331 case PropertyType
.DATE
:
332 return (T
) node
.getProperty(property
).getDate();
334 return (T
) node
.getProperty(property
).getString();
336 } catch (ClassCastException e
) {
337 throw new IllegalArgumentException(
338 "Cannot cast property of type " + PropertyType
.nameFromValue(p
.getType()), e
);
343 } catch (RepositoryException e
) {
344 throw new IllegalStateException("Cannot retrieve property " + property
+ " from " + node
);
348 /** Retrieves the {@link Session} related to this node. */
349 public static Session
session(Node node
) {
351 return node
.getSession();
352 } catch (RepositoryException e
) {
353 throw new IllegalStateException("Cannot retrieve session related to " + node
, e
);
358 * Saves the {@link Session} related to this node. Note that all other unrelated
359 * modifications in this session will also be saved.
361 public static void save(Node node
) {
363 Session session
= node
.getSession();
364 if (node
.isNodeType(NodeType
.MIX_LAST_MODIFIED
)) {
365 set(node
, Property
.JCR_LAST_MODIFIED
, Instant
.now());
366 set(node
, Property
.JCR_LAST_MODIFIED_BY
, session
.getUserID());
369 } catch (RepositoryException e
) {
370 throw new IllegalStateException("Cannot save session related to " + node
+ " in workspace "
371 + session(node
).getWorkspace().getName(), e
);
375 /** Login to a JCR repository. */
376 public static Session
login(Repository repository
, String workspace
) {
378 return repository
.login(workspace
);
379 } catch (RepositoryException e
) {
380 throw new IllegalArgumentException("Cannot login to repository", e
);
384 /** Safely and silently logs out a session. */
385 public static void logout(Session session
) {
388 if (session
.isLive())
390 } catch (Exception e
) {
399 * Add a single privilege to a node.
403 public static void addPrivilege(Node node
, String principal
, String privilege
) {
405 Session session
= node
.getSession();
406 JcrUtils
.addPrivilege(session
, node
.getPath(), principal
, privilege
);
407 } catch (RepositoryException e
) {
408 throw new IllegalStateException("Cannot add privilege " + privilege
+ " to " + node
, e
);
415 /** Get checked out status. */
416 public static boolean isCheckedOut(Node node
) {
418 return node
.isCheckedOut();
419 } catch (RepositoryException e
) {
420 throw new IllegalStateException("Cannot retrieve checked out status of " + node
, e
);
424 /** Check in this node. */
425 public static void checkin(Node node
) {
427 versionManager(node
).checkin(node
.getPath());
428 } catch (RepositoryException e
) {
429 throw new IllegalStateException("Cannot check in " + node
, e
);
433 /** Check out this node. */
434 public static void checkout(Node node
) {
436 versionManager(node
).checkout(node
.getPath());
437 } catch (RepositoryException e
) {
438 throw new IllegalStateException("Cannot check out " + node
, e
);
442 /** Get the {@link VersionManager} related to this node. */
443 public static VersionManager
versionManager(Node node
) {
445 return node
.getSession().getWorkspace().getVersionManager();
446 } catch (RepositoryException e
) {
447 throw new IllegalStateException("Cannot get version manager from " + node
, e
);
451 /** Get the {@link VersionHistory} related to this node. */
452 public static VersionHistory
getVersionHistory(Node node
) {
454 return versionManager(node
).getVersionHistory(node
.getPath());
455 } catch (RepositoryException e
) {
456 throw new IllegalStateException("Cannot get version history from " + node
, e
);
461 * The linear versions of this version history in reverse order and without the
464 public static List
<Version
> getLinearVersions(VersionHistory versionHistory
) {
466 List
<Version
> lst
= new ArrayList
<>();
467 VersionIterator vit
= versionHistory
.getAllLinearVersions();
468 while (vit
.hasNext())
469 lst
.add(vit
.nextVersion());
471 Collections
.reverse(lst
);
473 } catch (RepositoryException e
) {
474 throw new IllegalStateException("Cannot get linear versions from " + versionHistory
, e
);
478 /** The frozen node related to this {@link Version}. */
479 public static Node
getFrozenNode(Version version
) {
481 return version
.getFrozenNode();
482 } catch (RepositoryException e
) {
483 throw new IllegalStateException("Cannot get frozen node from " + version
, e
);
487 /** Get the base {@link Version} related to this node. */
488 public static Version
getBaseVersion(Node node
) {
490 return versionManager(node
).getBaseVersion(node
.getPath());
491 } catch (RepositoryException e
) {
492 throw new IllegalStateException("Cannot get base version from " + node
, e
);
500 * Returns the size of this file.
502 * @see NodeType#NT_FILE
504 public static long getFileSize(Node fileNode
) {
506 if (!fileNode
.isNodeType(NodeType
.NT_FILE
))
507 throw new IllegalArgumentException(fileNode
+ " must be a file.");
508 return getBinarySize(fileNode
.getNode(Node
.JCR_CONTENT
).getProperty(Property
.JCR_DATA
).getBinary());
509 } catch (RepositoryException e
) {
510 throw new IllegalStateException("Cannot get file size of " + fileNode
, e
);
514 /** Returns the size of this {@link Binary}. */
515 public static long getBinarySize(Binary binaryArg
) {
517 try (Bin binary
= new Bin(binaryArg
)) {
518 return binary
.getSize();
520 } catch (RepositoryException e
) {
521 throw new IllegalStateException("Cannot get file size of binary " + binaryArg
, e
);