import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.Principal;
import java.text.DateFormat;
import java.text.ParseException;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import javax.jcr.Binary;
import javax.jcr.Credentials;
+import javax.jcr.ImportUUIDBehavior;
import javax.jcr.NamespaceRegistry;
import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
-import javax.jcr.PropertyType;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.Workspace;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeType;
import javax.jcr.observation.EventListener;
import javax.jcr.query.Query;
import javax.jcr.security.Privilege;
import org.apache.commons.io.IOUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
/** Utility methods to simplify common JCR operations. */
public class JcrUtils {
- final private static Log log = LogFactory.getLog(JcrUtils.class);
+// final private static Log log = LogFactory.getLog(JcrUtils.class);
/**
* Not complete yet. See
}
}
+// /**
+// * Routine that get the child with this name, adding it if it does not already
+// * exist
+// */
+// public static Node getOrAdd(Node parent, String name, String primaryNodeType) throws RepositoryException {
+// return parent.hasNode(name) ? parent.getNode(name) : parent.addNode(name, primaryNodeType);
+// }
+
/**
- * Routine that get the child with this name, adding id it does not already
+ * Routine that get the child with this name, adding it if it does not already
* exist
*/
- public static Node getOrAdd(Node parent, String childName, String childPrimaryNodeType) throws RepositoryException {
- return parent.hasNode(childName) ? parent.getNode(childName) : parent.addNode(childName, childPrimaryNodeType);
+ public static Node getOrAdd(Node parent, String name, String primaryNodeType, String... mixinNodeTypes)
+ throws RepositoryException {
+ Node node;
+ if (parent.hasNode(name)) {
+ node = parent.getNode(name);
+ if (primaryNodeType != null && !node.isNodeType(primaryNodeType))
+ throw new IllegalArgumentException("Node " + node + " exists but is of primary node type "
+ + node.getPrimaryNodeType().getName() + ", not " + primaryNodeType);
+ for (String mixin : mixinNodeTypes) {
+ if (!node.isNodeType(mixin))
+ node.addMixin(mixin);
+ }
+ return node;
+ } else {
+ node = primaryNodeType != null ? parent.addNode(name, primaryNodeType) : parent.addNode(name);
+ for (String mixin : mixinNodeTypes) {
+ node.addMixin(mixin);
+ }
+ return node;
+ }
}
/**
- * Routine that get the child with this name, adding id it does not already
+ * Routine that get the child with this name, adding it if it does not already
* exist
*/
- public static Node getOrAdd(Node parent, String childName) throws RepositoryException {
- return parent.hasNode(childName) ? parent.getNode(childName) : parent.addNode(childName);
+ public static Node getOrAdd(Node parent, String name) throws RepositoryException {
+ return parent.hasNode(name) ? parent.getNode(name) : parent.addNode(name);
}
/** Convert a {@link NodeIterator} to a list of {@link Node} */
currentNode = currentNode.addNode(part);
if (versioning)
currentNode.addMixin(NodeType.MIX_VERSIONABLE);
- if (log.isTraceEnabled())
- log.debug("Added folder " + part + " as " + current);
+// if (log.isTraceEnabled())
+// log.debug("Added folder " + part + " as " + current);
} else {
currentNode = (Node) session.getItem(current.toString());
}
}
}
- /** Recursively outputs the contents of the given node. */
- public static void debug(Node node) {
- debug(node, log);
- }
-
- /** Recursively outputs the contents of the given node. */
- public static void debug(Node node, Log log) {
- try {
- // First output the node path
- log.debug(node.getPath());
- // Skip the virtual (and large!) jcr:system subtree
- if (node.getName().equals("jcr:system")) {
- return;
- }
-
- // Then the children nodes (recursive)
- NodeIterator it = node.getNodes();
- while (it.hasNext()) {
- Node childNode = it.nextNode();
- debug(childNode, log);
- }
-
- // Then output the properties
- PropertyIterator properties = node.getProperties();
- // log.debug("Property are : ");
-
- properties: while (properties.hasNext()) {
- Property property = properties.nextProperty();
- if (property.getType() == PropertyType.BINARY)
- continue properties;// skip
- if (property.getDefinition().isMultiple()) {
- // A multi-valued property, print all values
- Value[] values = property.getValues();
- for (int i = 0; i < values.length; i++) {
- log.debug(property.getPath() + "=" + values[i].getString());
- }
- } else {
- // A single-valued property
- log.debug(property.getPath() + "=" + property.getString());
- }
- }
- } catch (Exception e) {
- log.error("Could not debug " + node, e);
- }
-
- }
-
- /** Logs the effective access control policies */
- public static void logEffectiveAccessPolicies(Node node) {
- try {
- logEffectiveAccessPolicies(node.getSession(), node.getPath());
- } catch (RepositoryException e) {
- log.error("Cannot log effective access policies of " + node, e);
- }
- }
-
- /** Logs the effective access control policies */
- public static void logEffectiveAccessPolicies(Session session, String path) {
- if (!log.isDebugEnabled())
- return;
+// /** Recursively outputs the contents of the given node. */
+// public static void debug(Node node) {
+// debug(node, log);
+// }
+//
+// /** Recursively outputs the contents of the given node. */
+// public static void debug(Node node, Log log) {
+// try {
+// // First output the node path
+// log.debug(node.getPath());
+// // Skip the virtual (and large!) jcr:system subtree
+// if (node.getName().equals("jcr:system")) {
+// return;
+// }
+//
+// // Then the children nodes (recursive)
+// NodeIterator it = node.getNodes();
+// while (it.hasNext()) {
+// Node childNode = it.nextNode();
+// debug(childNode, log);
+// }
+//
+// // Then output the properties
+// PropertyIterator properties = node.getProperties();
+// // log.debug("Property are : ");
+//
+// properties: while (properties.hasNext()) {
+// Property property = properties.nextProperty();
+// if (property.getType() == PropertyType.BINARY)
+// continue properties;// skip
+// if (property.getDefinition().isMultiple()) {
+// // A multi-valued property, print all values
+// Value[] values = property.getValues();
+// for (int i = 0; i < values.length; i++) {
+// log.debug(property.getPath() + "=" + values[i].getString());
+// }
+// } else {
+// // A single-valued property
+// log.debug(property.getPath() + "=" + property.getString());
+// }
+// }
+// } catch (Exception e) {
+// log.error("Could not debug " + node, e);
+// }
+//
+// }
- try {
- AccessControlPolicy[] effectivePolicies = session.getAccessControlManager().getEffectivePolicies(path);
- if (effectivePolicies.length > 0) {
- for (AccessControlPolicy policy : effectivePolicies) {
- if (policy instanceof AccessControlList) {
- AccessControlList acl = (AccessControlList) policy;
- log.debug("Access control list for " + path + "\n" + accessControlListSummary(acl));
- }
- }
- } else {
- log.debug("No effective access control policy for " + path);
- }
- } catch (RepositoryException e) {
- log.error("Cannot log effective access policies of " + path, e);
- }
- }
+// /** Logs the effective access control policies */
+// public static void logEffectiveAccessPolicies(Node node) {
+// try {
+// logEffectiveAccessPolicies(node.getSession(), node.getPath());
+// } catch (RepositoryException e) {
+// log.error("Cannot log effective access policies of " + node, e);
+// }
+// }
+//
+// /** Logs the effective access control policies */
+// public static void logEffectiveAccessPolicies(Session session, String path) {
+// if (!log.isDebugEnabled())
+// return;
+//
+// try {
+// AccessControlPolicy[] effectivePolicies = session.getAccessControlManager().getEffectivePolicies(path);
+// if (effectivePolicies.length > 0) {
+// for (AccessControlPolicy policy : effectivePolicies) {
+// if (policy instanceof AccessControlList) {
+// AccessControlList acl = (AccessControlList) policy;
+// log.debug("Access control list for " + path + "\n" + accessControlListSummary(acl));
+// }
+// }
+// } else {
+// log.debug("No effective access control policy for " + path);
+// }
+// } catch (RepositoryException e) {
+// log.error("Cannot log effective access policies of " + path, e);
+// }
+// }
/** Returns a human-readable summary of this access control list. */
public static String accessControlListSummary(AccessControlList acl) {
}
}
+ /** Copy the whole workspace via a system view XML. */
+ public static void copyWorkspaceXml(Session fromSession, Session toSession) {
+ Workspace fromWorkspace = fromSession.getWorkspace();
+ Workspace toWorkspace = toSession.getWorkspace();
+ String errorMsg = "Cannot copy workspace " + fromWorkspace + " to " + toWorkspace + " via XML.";
+
+ try (PipedInputStream in = new PipedInputStream(1024 * 1024);) {
+ new Thread(() -> {
+ try (PipedOutputStream out = new PipedOutputStream(in)) {
+ fromSession.exportSystemView("/", out, false, false);
+ out.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(errorMsg, e);
+ } catch (RepositoryException e) {
+ throw new JcrException(errorMsg, e);
+ }
+ }, "Copy workspace" + fromWorkspace + " to " + toWorkspace).start();
+
+ toSession.importXML("/", in, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
+ toSession.save();
+ } catch (IOException e) {
+ throw new RuntimeException(errorMsg, e);
+ } catch (RepositoryException e) {
+ throw new JcrException(errorMsg, e);
+ }
+ }
+
/**
* Copies recursively the content of a node to another one. Do NOT copy the
* property values of {@link NodeType#MIX_CREATED} and
if (toNode.getDefinition().isProtected())
return;
+ // add mixins
+ for (NodeType mixinType : fromNode.getMixinNodeTypes()) {
+ try {
+ toNode.addMixin(mixinType.getName());
+ } catch (NoSuchNodeTypeException e) {
+ // ignore unknown mixins
+ // TODO log it
+ }
+ }
+
// process properties
PropertyIterator pit = fromNode.getProperties();
properties: while (pit.hasNext()) {
// 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());
- }
+ updateLastModified(toNode, true);
// process children nodes
NodeIterator nit = fromNode.getNodes();
Node toChild;
if (toNode.hasNode(nodeRelPath))
toChild = toNode.getNode(nodeRelPath);
- else
- toChild = toNode.addNode(fromChild.getName(), fromChild.getPrimaryNodeType().getName());
+ else {
+ try {
+ toChild = toNode.addNode(fromChild.getName(), fromChild.getPrimaryNodeType().getName());
+ } catch (NoSuchNodeTypeException e) {
+ // ignore unknown primary types
+ // TODO log it
+ return;
+ }
+ }
copy(fromChild, toChild);
}
} catch (RepositoryException e) {
try {
discardQuietly(node.getSession());
} catch (RepositoryException e) {
- log.warn("Cannot quietly discard session of node " + node + ": " + e.getMessage());
+ // silent
}
}
if (session != null)
session.refresh(false);
} catch (RepositoryException e) {
- log.warn("Cannot quietly discard session " + session + ": " + e.getMessage());
+ // silent
}
}
unregisterQuietly(node.getSession().getWorkspace(), eventListener);
} catch (RepositoryException e) {
// silent
- if (log.isTraceEnabled())
- log.trace("Could not unregister event listener " + eventListener);
}
}
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,
+ * Checks whether {@link Property#JCR_LAST_MODIFIED} or (afterwards)
+ * {@link Property#JCR_CREATED} are set and returns it as an {@link Instant}.
+ */
+ public static Instant getModified(Node node) {
+ Calendar calendar = null;
+ try {
+ if (node.hasProperty(Property.JCR_LAST_MODIFIED))
+ calendar = node.getProperty(Property.JCR_LAST_MODIFIED).getDate();
+ else if (node.hasProperty(Property.JCR_CREATED))
+ calendar = node.getProperty(Property.JCR_CREATED).getDate();
+ else
+ throw new IllegalArgumentException("No modification time found in " + node);
+ return calendar.toInstant();
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot get modification time for " + node, e);
+ }
+
+ }
+
+ /**
+ * Get {@link Property#JCR_CREATED} as an {@link Instant}, if it is set.
+ */
+ public static Instant getCreated(Node node) {
+ Calendar calendar = null;
+ try {
+ if (node.hasProperty(Property.JCR_CREATED))
+ calendar = node.getProperty(Property.JCR_CREATED).getDate();
+ else
+ throw new IllegalArgumentException("No created time found in " + node);
+ return calendar.toInstant();
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot get created time for " + node, e);
+ }
+
+ }
+
+ /**
+ * 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.
+ */
+ public static void updateLastModified(Node node) {
+ updateLastModified(node, false);
+ }
+
+ /**
+ * 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) {
+ public static void updateLastModified(Node node, boolean addMixin) {
try {
- if (!node.isNodeType(NodeType.MIX_LAST_MODIFIED))
+ if (addMixin && !node.isNodeType(NodeType.MIX_LAST_MODIFIED))
node.addMixin(NodeType.MIX_LAST_MODIFIED);
node.setProperty(Property.JCR_LAST_MODIFIED, new GregorianCalendar());
node.setProperty(Property.JCR_LAST_MODIFIED_BY, node.getSession().getUserID());
* @param untilPath the base path, null is equivalent to "/"
*/
public static void updateLastModifiedAndParents(Node node, String untilPath) {
+ updateLastModifiedAndParents(node, untilPath, true);
+ }
+
+ /**
+ * Update lastModified recursively until this parent.
+ *
+ * @param node the node
+ * @param untilPath the base path, null is equivalent to "/"
+ */
+ public static void updateLastModifiedAndParents(Node node, String untilPath, boolean addMixin) {
try {
if (untilPath != null && !node.getPath().startsWith(untilPath))
throw new IllegalArgumentException(node + " is not under " + untilPath);
- updateLastModified(node);
+ updateLastModified(node, addMixin);
if (untilPath == null) {
if (!node.getPath().equals("/"))
- updateLastModifiedAndParents(node.getParent(), untilPath);
+ updateLastModifiedAndParents(node.getParent(), untilPath, addMixin);
} else {
if (!node.getPath().equals(untilPath))
- updateLastModifiedAndParents(node.getParent(), untilPath);
+ updateLastModifiedAndParents(node.getParent(), untilPath, addMixin);
}
} catch (RepositoryException e) {
throw new JcrException("Cannot update lastModified from " + node + " until " + untilPath, e);
Privilege[] privileges = privs.toArray(new Privilege[privs.size()]);
acl.addAccessControlEntry(principal, privileges);
acm.setPolicy(path, acl);
- if (log.isDebugEnabled()) {
- StringBuffer privBuf = new StringBuffer();
- for (Privilege priv : privs)
- privBuf.append(priv.getName());
- log.debug("Added privileges " + privBuf + " to " + principal.getName() + " on " + path + " in '"
- + session.getWorkspace().getName() + "'");
- }
+// if (log.isDebugEnabled()) {
+// StringBuffer privBuf = new StringBuffer();
+// for (Privilege priv : privs)
+// privBuf.append(priv.getName());
+// log.debug("Added privileges " + privBuf + " to " + principal.getName() + " on " + path + " in '"
+// + session.getWorkspace().getName() + "'");
+// }
session.refresh(true);
session.save();
return true;
toNode.getSession().save();
count++;
- if (log.isDebugEnabled())
- log.debug("Copied file " + fromChild.getPath());
+// if (log.isDebugEnabled())
+// log.debug("Copied file " + fromChild.getPath());
if (monitor != null)
monitor.worked(1);
} else if (fromChild.isNodeType(NodeType.NT_FOLDER) && recursive) {