]> git.argeo.org Git - lgpl/argeo-commons.git/blobdiff - server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java
Add discard quietly for node session
[lgpl/argeo-commons.git] / server / runtime / org.argeo.server.jcr / src / main / java / org / argeo / jcr / JcrUtils.java
index bc7862f5fea23b5a3a2b4d935cfbb1bed2d13ebc..f530f170b7fe4a0637d2eb72b75b4470dba07199 100644 (file)
@@ -41,7 +41,9 @@ import javax.jcr.RepositoryException;
 import javax.jcr.RepositoryFactory;
 import javax.jcr.Session;
 import javax.jcr.Value;
+import javax.jcr.Workspace;
 import javax.jcr.nodetype.NodeType;
+import javax.jcr.observation.EventListener;
 import javax.jcr.query.Query;
 import javax.jcr.query.QueryResult;
 import javax.jcr.query.qom.Constraint;
@@ -365,11 +367,16 @@ public class JcrUtils implements ArgeoJcrConstants {
        }
 
        /**
-        * Copies recursively the content of a node to another one. Mixin are NOT
-        * copied.
+        * Copies recursively the content of a node to another one. Do NOT copy the
+        * property values of {@link NodeType#MIX_CREATED} and
+        * {@link NodeType#MIX_LAST_MODIFIED}, but update the
+        * {@link Property#JCR_LAST_MODIFIED} and
+        * {@link Property#JCR_LAST_MODIFIED_BY} properties if the target node has
+        * the {@link NodeType#MIX_LAST_MODIFIED} mixin.
         */
        public static void copy(Node fromNode, Node toNode) {
                try {
+                       // process properties
                        PropertyIterator pit = fromNode.getProperties();
                        properties: while (pit.hasNext()) {
                                Property fromProperty = pit.nextProperty();
@@ -379,10 +386,32 @@ public class JcrUtils implements ArgeoJcrConstants {
                                                                .isProtected())
                                        continue properties;
 
-                               toNode.setProperty(fromProperty.getName(),
-                                               fromProperty.getValue());
+                               if (fromProperty.getDefinition().isProtected())
+                                       continue properties;
+
+                               if (propertyName.equals("jcr:created")
+                                               || propertyName.equals("jcr:createdBy")
+                                               || propertyName.equals("jcr:lastModified")
+                                               || propertyName.equals("jcr:lastModifiedBy"))
+                                       continue properties;
+
+                               if (fromProperty.isMultiple()) {
+                                       toNode.setProperty(propertyName, fromProperty.getValues());
+                               } else {
+                                       toNode.setProperty(propertyName, fromProperty.getValue());
+                               }
                        }
 
+                       // update jcr:lastModified and jcr:lastModifiedBy in toNode in case
+                       // they existed, before adding the mixins
+                       updateLastModified(toNode);
+
+                       // add mixins
+                       for (NodeType mixinType : fromNode.getMixinNodeTypes()) {
+                               toNode.addMixin(mixinType.getName());
+                       }
+
+                       // process children nodes
                        NodeIterator nit = fromNode.getNodes();
                        while (nit.hasNext()) {
                                Node fromChild = nit.nextNode();
@@ -623,6 +652,21 @@ public class JcrUtils implements ArgeoJcrConstants {
                }
        }
 
+       /**
+        * Discards the current changes in the session attached to this node. To be
+        * used typically in a catch block.
+        * 
+        * @see #discardQuietly(Session)
+        */
+       public static void discardUnderlyingSessionQuietly(Node node) {
+               try {
+                       discardQuietly(node.getSession());
+               } catch (RepositoryException e) {
+                       log.warn("Cannot quietly discard session of node " + node + ": "
+                                       + e.getMessage());
+               }
+       }
+
        /**
         * Discards the current changes in a session by calling
         * {@link Session#refresh(boolean)} with <code>false</code>, only logging
@@ -650,6 +694,24 @@ public class JcrUtils implements ArgeoJcrConstants {
                return getUserHome(session, userID);
        }
 
+       /**
+        * Returns user home has path, embedding exceptions. Contrary to
+        * {@link #getUserHome(Session)}, it never returns null but throws and
+        * exception if not found.
+        */
+       public static String getUserHomePath(Session session) {
+               String userID = session.getUserID();
+               try {
+                       Node userHome = getUserHome(session, userID);
+                       if (userHome != null)
+                               return userHome.getPath();
+                       else
+                               throw new ArgeoException("No home registered for " + userID);
+               } catch (RepositoryException e) {
+                       throw new ArgeoException("Cannot find user home path", e);
+               }
+       }
+
        /** Get the profile of the user attached to this session. */
        public static Node getUserProfile(Session session) {
                String userID = session.getUserID();
@@ -709,6 +771,7 @@ public class JcrUtils implements ArgeoJcrConstants {
                }
        }
 
+       /** Creates an Argeo user home. */
        public static Node createUserHome(Session session, String homeBasePath,
                        String username) {
                try {
@@ -738,4 +801,57 @@ public class JcrUtils implements ArgeoJcrConstants {
                                        + username, e);
                }
        }
+
+       /**
+        * Quietly unregisters an {@link EventListener} from the udnerlying
+        * workspace of this node.
+        */
+       public static void unregisterQuietly(Node node, EventListener eventListener) {
+               try {
+                       unregisterQuietly(node.getSession().getWorkspace(), eventListener);
+               } catch (RepositoryException e) {
+                       // silent
+                       if (log.isTraceEnabled())
+                               log.trace("Could not unregister event listener "
+                                               + eventListener);
+               }
+       }
+
+       /** Quietly unregisters an {@link EventListener} from this workspace */
+       public static void unregisterQuietly(Workspace workspace,
+                       EventListener eventListener) {
+               if (eventListener == null)
+                       return;
+               try {
+                       workspace.getObservationManager()
+                                       .removeEventListener(eventListener);
+               } catch (RepositoryException e) {
+                       // silent
+                       if (log.isTraceEnabled())
+                               log.trace("Could not unregister event listener "
+                                               + eventListener);
+               }
+       }
+
+       /**
+        * If this node is has the {@link NodeType#MIX_LAST_MODIFIED} mixin, it
+        * updates the {@link Property#JCR_LAST_MODIFIED} property with the current
+        * time and the {@link Property#JCR_LAST_MODIFIED_BY} property with the
+        * underlying session user id. In Jackrabbit 2.x, <a
+        * href="https://issues.apache.org/jira/browse/JCR-2233">these properties
+        * are not automatically updated</a>, hence the need for manual update. The
+        * session is not saved.
+        */
+       public static void updateLastModified(Node node) {
+               try {
+                       if (node.isNodeType(NodeType.MIX_LAST_MODIFIED)) {
+                               node.setProperty(Property.JCR_LAST_MODIFIED,
+                                               new GregorianCalendar());
+                               node.setProperty(Property.JCR_LAST_MODIFIED_BY, node
+                                               .getSession().getUserID());
+                       }
+               } catch (RepositoryException e) {
+                       throw new ArgeoException("Cannot update last modified", e);
+               }
+       }
 }