Improve JCR utilities.
[lgpl/argeo-commons.git] / org.argeo.jcr / src / org / argeo / jcr / Jcr.java
index f8ad9c79cca88dd58526b0320612940e61993c8d..230921d551f191ae65f879b998308936d7aff248 100644 (file)
@@ -1,9 +1,16 @@
 package org.argeo.jcr;
 
+import java.math.BigDecimal;
+import java.time.Instant;
 import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.GregorianCalendar;
 import java.util.Iterator;
 import java.util.List;
 
+import javax.jcr.Binary;
 import javax.jcr.ItemNotFoundException;
 import javax.jcr.Node;
 import javax.jcr.NodeIterator;
@@ -13,6 +20,12 @@ import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.Value;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.security.Privilege;
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionHistory;
+import javax.jcr.version.VersionIterator;
+import javax.jcr.version.VersionManager;
 
 /**
  * Utility class whose purpose is to make using JCR less verbose by
@@ -200,6 +213,48 @@ public class Jcr {
                }
        }
 
+       /**
+        * Set a property to the given value, or remove it if the value is
+        * <code>null</code>.
+        * 
+        * @throws IllegalStateException caused by {@link RepositoryException}
+        */
+       public static void set(Node node, String property, Object value) {
+               try {
+                       if (!node.hasProperty(property))
+                               throw new IllegalArgumentException("No property " + property + " in " + node);
+                       Property prop = node.getProperty(property);
+                       if (value == null) {
+                               prop.remove();
+                               return;
+                       }
+
+                       if (value instanceof String)
+                               prop.setValue((String) value);
+                       else if (value instanceof Long)
+                               prop.setValue((Long) value);
+                       else if (value instanceof Double)
+                               prop.setValue((Double) value);
+                       else if (value instanceof Calendar)
+                               prop.setValue((Calendar) value);
+                       else if (value instanceof BigDecimal)
+                               prop.setValue((BigDecimal) value);
+                       else if (value instanceof Boolean)
+                               prop.setValue((Boolean) value);
+                       else if (value instanceof byte[])
+                               JcrUtils.setBinaryAsBytes(prop, (byte[]) value);
+                       else if (value instanceof Instant) {
+                               Instant instant = (Instant) value;
+                               GregorianCalendar calendar = new GregorianCalendar();
+                               calendar.setTime(Date.from(instant));
+                               prop.setValue(calendar);
+                       } else // try with toString()
+                               prop.setValue(value.toString());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot set property " + property + " of " + node + " to " + value, e);
+               }
+       }
+
        /**
         * Get property as {@link String}.
         * 
@@ -290,6 +345,33 @@ public class Jcr {
                }
        }
 
+       /** Retrieves the {@link Session} related to this node. */
+       public static Session session(Node node) {
+               try {
+                       return node.getSession();
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot retrieve session related to " + node, e);
+               }
+       }
+
+       /**
+        * Saves the {@link Session} related to this node. Note that all other unrelated
+        * modifications in this session will also be saved.
+        */
+       public static void save(Node node) {
+               try {
+                       Session session = node.getSession();
+                       if (node.isNodeType(NodeType.MIX_LAST_MODIFIED)) {
+                               set(node, Property.JCR_LAST_MODIFIED, Instant.now());
+                               set(node, Property.JCR_LAST_MODIFIED_BY, session.getUserID());
+                       }
+                       session.save();
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot save session related to " + node + " in workspace "
+                                       + session(node).getWorkspace().getName(), e);
+               }
+       }
+
        /** Login to a JCR repository. */
        public static Session login(Repository repository, String workspace) {
                try {
@@ -310,6 +392,136 @@ public class Jcr {
                }
        }
 
+       /*
+        * SECURITY
+        */
+       /**
+        * Add a single privilege to a node.
+        * 
+        * @see Privilege
+        */
+       public static void addPrivilege(Node node, String principal, String privilege) {
+               try {
+                       Session session = node.getSession();
+                       JcrUtils.addPrivilege(session, node.getPath(), principal, privilege);
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot add privilege " + privilege + " to " + node, e);
+               }
+       }
+
+       /*
+        * VERSIONING
+        */
+       /** Get checked out status. */
+       public static boolean isCheckedOut(Node node) {
+               try {
+                       return node.isCheckedOut();
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot retrieve checked out status of " + node, e);
+               }
+       }
+
+       /** Check in this node. */
+       public static void checkin(Node node) {
+               try {
+                       versionManager(node).checkin(node.getPath());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot check in " + node, e);
+               }
+       }
+
+       /** Check out this node. */
+       public static void checkout(Node node) {
+               try {
+                       versionManager(node).checkout(node.getPath());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot check out " + node, e);
+               }
+       }
+
+       /** Get the {@link VersionManager} related to this node. */
+       public static VersionManager versionManager(Node node) {
+               try {
+                       return node.getSession().getWorkspace().getVersionManager();
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot get version manager from " + node, e);
+               }
+       }
+
+       /** Get the {@link VersionHistory} related to this node. */
+       public static VersionHistory getVersionHistory(Node node) {
+               try {
+                       return versionManager(node).getVersionHistory(node.getPath());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot get version history from " + node, e);
+               }
+       }
+
+       /**
+        * The linear versions of this version history in reverse order and without the
+        * root version.
+        */
+       public static List<Version> getLinearVersions(VersionHistory versionHistory) {
+               try {
+                       List<Version> lst = new ArrayList<>();
+                       VersionIterator vit = versionHistory.getAllLinearVersions();
+                       while (vit.hasNext())
+                               lst.add(vit.nextVersion());
+                       lst.remove(0);
+                       Collections.reverse(lst);
+                       return lst;
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot get linear versions from " + versionHistory, e);
+               }
+       }
+
+       /** The frozen node related to this {@link Version}. */
+       public static Node getFrozenNode(Version version) {
+               try {
+                       return version.getFrozenNode();
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot get frozen node from " + version, e);
+               }
+       }
+
+       /** Get the base {@link Version} related to this node. */
+       public static Version getBaseVersion(Node node) {
+               try {
+                       return versionManager(node).getBaseVersion(node.getPath());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot get base version from " + node, e);
+               }
+       }
+
+       /*
+        * FILES
+        */
+       /**
+        * Returns the size of this file.
+        * 
+        * @see NodeType#NT_FILE
+        */
+       public static long getFileSize(Node fileNode) {
+               try {
+                       if (!fileNode.isNodeType(NodeType.NT_FILE))
+                               throw new IllegalArgumentException(fileNode + " must be a file.");
+                       return getBinarySize(fileNode.getNode(Node.JCR_CONTENT).getProperty(Property.JCR_DATA).getBinary());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot get file size of " + fileNode, e);
+               }
+       }
+
+       /** Returns the size of this {@link Binary}. */
+       public static long getBinarySize(Binary binaryArg) {
+               try {
+                       try (Bin binary = new Bin(binaryArg)) {
+                               return binary.getSize();
+                       }
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot get file size of binary " + binaryArg, e);
+               }
+       }
+
        /** Singleton. */
        private Jcr() {