1   package org.argeo.jcr;
2   
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;
8   import java.util.Date;
9   import java.util.GregorianCalendar;
10  import java.util.Iterator;
11  import java.util.List;
12  
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;
29  
30  
31  
32  
33  
34  
35  
36  
37  public class Jcr {
38  
39  	
40  
41  
42  
43  	public static boolean isNodeType(Node node, String nodeTypeName) {
44  		try {
45  			return node.isNodeType(nodeTypeName);
46  		} catch (RepositoryException e) {
47  			throw new IllegalStateException("Cannot get whether " + node + " is of type " + nodeTypeName, e);
48  		}
49  	}
50  
51  	
52  
53  
54  
55  	public static boolean hasNodes(Node node) {
56  		try {
57  			return node.hasNodes();
58  		} catch (RepositoryException e) {
59  			throw new IllegalStateException("Cannot get whether " + node + " has children.", e);
60  		}
61  	}
62  
63  	
64  
65  
66  
67  	public static Node getParent(Node node) {
68  		try {
69  			return isRoot(node) ? null : node.getParent();
70  		} catch (RepositoryException e) {
71  			throw new IllegalStateException("Cannot get parent of " + node, e);
72  		}
73  	}
74  
75  	
76  
77  
78  
79  
80  	public static boolean isRoot(Node node) {
81  		try {
82  			return node.getDepth() == 0;
83  		} catch (RepositoryException e) {
84  			throw new IllegalStateException("Cannot get depth of " + node, e);
85  		}
86  	}
87  
88  	
89  
90  
91  
92  	public static String getPath(Node node) {
93  		try {
94  			return node.getPath();
95  		} catch (RepositoryException e) {
96  			throw new IllegalStateException("Cannot get path of " + node, e);
97  		}
98  	}
99  
100 	
101 
102 
103 
104 	public static String getIdentifier(Node node) {
105 		try {
106 			return node.getIdentifier();
107 		} catch (RepositoryException e) {
108 			throw new IllegalStateException("Cannot get identifier of " + node, e);
109 		}
110 	}
111 
112 	
113 
114 
115 
116 	public static String getName(Node node) {
117 		try {
118 			return node.getName();
119 		} catch (RepositoryException e) {
120 			throw new IllegalStateException("Cannot get name of " + node, e);
121 		}
122 	}
123 
124 	
125 	@SuppressWarnings("unchecked")
126 	public static Iterable<Node> iterate(NodeIterator nodeIterator) {
127 		return new Iterable<Node>() {
128 
129 			@Override
130 			public Iterator<Node> iterator() {
131 				return nodeIterator;
132 			}
133 		};
134 	}
135 
136 	
137 
138 
139 
140 
141 	public static Iterable<Node> nodes(Node node) {
142 		try {
143 			return iterate(node.getNodes());
144 		} catch (RepositoryException e) {
145 			throw new IllegalStateException("Cannot get children of " + node, e);
146 		}
147 	}
148 
149 	
150 
151 
152 
153 
154 	public static List<Node> getNodes(Node node) {
155 		List<Node> nodes = new ArrayList<>();
156 		try {
157 			if (node.hasNodes()) {
158 				NodeIterator nit = node.getNodes();
159 				while (nit.hasNext())
160 					nodes.add(nit.nextNode());
161 				return nodes;
162 			} else
163 				return nodes;
164 		} catch (RepositoryException e) {
165 			throw new IllegalStateException("Cannot get children of " + node, e);
166 		}
167 	}
168 
169 	
170 
171 
172 
173 
174 	public static Node getNode(Node node, String child) {
175 		try {
176 			if (node.hasNode(child))
177 				return node.getNode(child);
178 			else
179 				return null;
180 		} catch (RepositoryException e) {
181 			throw new IllegalStateException("Cannot get child of " + node, e);
182 		}
183 	}
184 
185 	
186 
187 
188 
189 
190 	public static Node getNode(Session session, String path) {
191 		try {
192 			if (session.nodeExists(path))
193 				return session.getNode(path);
194 			else
195 				return null;
196 		} catch (RepositoryException e) {
197 			throw new IllegalStateException("Cannot get node " + path, e);
198 		}
199 	}
200 
201 	
202 
203 
204 
205 
206 	public static Node getNodeById(Session session, String id) {
207 		try {
208 			return session.getNodeByIdentifier(id);
209 		} catch (ItemNotFoundException e) {
210 			return null;
211 		} catch (RepositoryException e) {
212 			throw new IllegalStateException("Cannot get node with id " + id, e);
213 		}
214 	}
215 
216 	
217 
218 
219 
220 
221 
222 	public static void set(Node node, String property, Object value) {
223 		try {
224 			if (!node.hasProperty(property))
225 				throw new IllegalArgumentException("No property " + property + " in " + node);
226 			Property prop = node.getProperty(property);
227 			if (value == null) {
228 				prop.remove();
229 				return;
230 			}
231 
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 
252 				prop.setValue(value.toString());
253 		} catch (RepositoryException e) {
254 			throw new IllegalStateException("Cannot set property " + property + " of " + node + " to " + value, e);
255 		}
256 	}
257 
258 	
259 
260 
261 
262 
263 
264 
265 
266 	public static String get(Node node, String property) {
267 		return get(node, property, null);
268 	}
269 
270 	
271 
272 
273 
274 
275 
276 
277 
278 	public static String get(Node node, String property, String defaultValue) {
279 		try {
280 			if (node.hasProperty(property))
281 				return node.getProperty(property).getString();
282 			else
283 				return defaultValue;
284 		} catch (RepositoryException e) {
285 			throw new IllegalStateException("Cannot retrieve property " + property + " from " + node);
286 		}
287 	}
288 
289 	
290 
291 
292 
293 
294 
295 
296 	public static Value getValue(Node node, String property) {
297 		try {
298 			if (node.hasProperty(property))
299 				return node.getProperty(property).getValue();
300 			else
301 				return null;
302 		} catch (RepositoryException e) {
303 			throw new IllegalStateException("Cannot retrieve property " + property + " from " + node);
304 		}
305 	}
306 
307 	
308 
309 
310 
311 
312 
313 
314 
315 
316 	@SuppressWarnings("unchecked")
317 	public static <T> T getAs(Node node, String property, T defaultValue) {
318 		try {
319 			if (node.hasProperty(property)) {
320 				Property p = node.getProperty(property);
321 				try {
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();
333 					default:
334 						return (T) node.getProperty(property).getString();
335 					}
336 				} catch (ClassCastException e) {
337 					throw new IllegalArgumentException(
338 							"Cannot cast property of type " + PropertyType.nameFromValue(p.getType()), e);
339 				}
340 			} else {
341 				return defaultValue;
342 			}
343 		} catch (RepositoryException e) {
344 			throw new IllegalStateException("Cannot retrieve property " + property + " from " + node);
345 		}
346 	}
347 
348 	
349 	public static Session session(Node node) {
350 		try {
351 			return node.getSession();
352 		} catch (RepositoryException e) {
353 			throw new IllegalStateException("Cannot retrieve session related to " + node, e);
354 		}
355 	}
356 
357 	
358 
359 
360 
361 	public static void save(Node node) {
362 		try {
363 			Session session = node.getSession();
364 
365 
366 
367 
368 			if (session.hasPendingChanges())
369 				session.save();
370 		} catch (RepositoryException e) {
371 			throw new IllegalStateException("Cannot save session related to " + node + " in workspace "
372 					+ session(node).getWorkspace().getName(), e);
373 		}
374 	}
375 
376 	
377 	public static Session login(Repository repository, String workspace) {
378 		try {
379 			return repository.login(workspace);
380 		} catch (RepositoryException e) {
381 			throw new IllegalArgumentException("Cannot login to repository", e);
382 		}
383 	}
384 
385 	
386 	public static void logout(Session session) {
387 		try {
388 			if (session != null)
389 				if (session.isLive())
390 					session.logout();
391 		} catch (Exception e) {
392 			
393 		}
394 	}
395 
396 	
397 
398 
399 	
400 
401 
402 
403 
404 	public static void addPrivilege(Node node, String principal, String privilege) {
405 		try {
406 			Session session = node.getSession();
407 			JcrUtils.addPrivilege(session, node.getPath(), principal, privilege);
408 		} catch (RepositoryException e) {
409 			throw new IllegalStateException("Cannot add privilege " + privilege + " to " + node, e);
410 		}
411 	}
412 
413 	
414 
415 
416 	
417 	public static boolean isCheckedOut(Node node) {
418 		try {
419 			return node.isCheckedOut();
420 		} catch (RepositoryException e) {
421 			throw new IllegalStateException("Cannot retrieve checked out status of " + node, e);
422 		}
423 	}
424 
425 	
426 	public static void checkpoint(Node node) {
427 		try {
428 			versionManager(node).checkpoint(node.getPath());
429 		} catch (RepositoryException e) {
430 			throw new IllegalStateException("Cannot check in " + node, e);
431 		}
432 	}
433 
434 	
435 	public static void checkin(Node node) {
436 		try {
437 			versionManager(node).checkin(node.getPath());
438 		} catch (RepositoryException e) {
439 			throw new IllegalStateException("Cannot check in " + node, e);
440 		}
441 	}
442 
443 	
444 	public static void checkout(Node node) {
445 		try {
446 			versionManager(node).checkout(node.getPath());
447 		} catch (RepositoryException e) {
448 			throw new IllegalStateException("Cannot check out " + node, e);
449 		}
450 	}
451 
452 	
453 	public static VersionManager versionManager(Node node) {
454 		try {
455 			return node.getSession().getWorkspace().getVersionManager();
456 		} catch (RepositoryException e) {
457 			throw new IllegalStateException("Cannot get version manager from " + node, e);
458 		}
459 	}
460 
461 	
462 	public static VersionHistory getVersionHistory(Node node) {
463 		try {
464 			return versionManager(node).getVersionHistory(node.getPath());
465 		} catch (RepositoryException e) {
466 			throw new IllegalStateException("Cannot get version history from " + node, e);
467 		}
468 	}
469 
470 	
471 
472 
473 
474 	public static List<Version> getLinearVersions(VersionHistory versionHistory) {
475 		try {
476 			List<Version> lst = new ArrayList<>();
477 			VersionIterator vit = versionHistory.getAllLinearVersions();
478 			while (vit.hasNext())
479 				lst.add(vit.nextVersion());
480 			lst.remove(0);
481 			Collections.reverse(lst);
482 			return lst;
483 		} catch (RepositoryException e) {
484 			throw new IllegalStateException("Cannot get linear versions from " + versionHistory, e);
485 		}
486 	}
487 
488 	
489 	public static Node getFrozenNode(Version version) {
490 		try {
491 			return version.getFrozenNode();
492 		} catch (RepositoryException e) {
493 			throw new IllegalStateException("Cannot get frozen node from " + version, e);
494 		}
495 	}
496 
497 	
498 	public static Version getBaseVersion(Node node) {
499 		try {
500 			return versionManager(node).getBaseVersion(node.getPath());
501 		} catch (RepositoryException e) {
502 			throw new IllegalStateException("Cannot get base version from " + node, e);
503 		}
504 	}
505 
506 	
507 
508 
509 	
510 
511 
512 
513 
514 	public static long getFileSize(Node fileNode) {
515 		try {
516 			if (!fileNode.isNodeType(NodeType.NT_FILE))
517 				throw new IllegalArgumentException(fileNode + " must be a file.");
518 			return getBinarySize(fileNode.getNode(Node.JCR_CONTENT).getProperty(Property.JCR_DATA).getBinary());
519 		} catch (RepositoryException e) {
520 			throw new IllegalStateException("Cannot get file size of " + fileNode, e);
521 		}
522 	}
523 
524 	
525 	public static long getBinarySize(Binary binaryArg) {
526 		try {
527 			try (Bin binary = new Bin(binaryArg)) {
528 				return binary.getSize();
529 			}
530 		} catch (RepositoryException e) {
531 			throw new IllegalStateException("Cannot get file size of binary " + binaryArg, e);
532 		}
533 	}
534 
535 	
536 	private Jcr() {
537 
538 	}
539 }