-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package org.argeo.jcr;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
import java.net.MalformedURLException;
import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
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 java.util.TreeMap;
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.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;
-import org.argeo.util.DigestUtils;
/** 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
* http://www.day.com/specs/jcr/2.0/3_Repository_Model.html#3.2.2%20Local
* %20Names
*/
- public final static char[] INVALID_NAME_CHARACTERS = { '/', ':', '[', ']', '|',
- '*', /*
- * invalid XML chars :
- */
- '<', '>', '&' };
+ public final static char[] INVALID_NAME_CHARACTERS = { '/', ':', '[', ']', '|', '*', /* invalid for XML: */ '<',
+ '>', '&' };
/** Prevents instantiation */
private JcrUtils() {
* Queries one single node.
*
* @return one single node or null if none was found
- * @throws ArgeoJcrException
- * if more than one node was found
+ * @throws JcrException if more than one node was found
*/
public static Node querySingleNode(Query query) {
NodeIterator nodeIterator;
QueryResult queryResult = query.execute();
nodeIterator = queryResult.getNodes();
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot execute query " + query, e);
+ throw new JcrException("Cannot execute query " + query, e);
}
Node node;
if (nodeIterator.hasNext())
return null;
if (nodeIterator.hasNext())
- throw new ArgeoJcrException("Query returned more than one node.");
+ throw new IllegalArgumentException("Query returned more than one node.");
return node;
}
if (path.equals("/"))
return "";
if (path.charAt(0) != '/')
- throw new ArgeoJcrException("Path " + path + " must start with a '/'");
+ throw new IllegalArgumentException("Path " + path + " must start with a '/'");
String pathT = path;
if (pathT.charAt(pathT.length() - 1) == '/')
pathT = pathT.substring(0, pathT.length() - 2);
/** Retrieves the parent path of the provided path */
public static String parentPath(String path) {
if (path.equals("/"))
- throw new ArgeoJcrException("Root path '/' has no parent path");
+ throw new IllegalArgumentException("Root path '/' has no parent path");
if (path.charAt(0) != '/')
- throw new ArgeoJcrException("Path " + path + " must start with a '/'");
+ throw new IllegalArgumentException("Path " + path + " must start with a '/'");
String pathT = path;
if (pathT.charAt(pathT.length() - 1) == '/')
pathT = pathT.substring(0, pathT.length() - 2);
path.append(u.getPath());
return path.toString();
} catch (MalformedURLException e) {
- throw new ArgeoJcrException("Cannot generate URL path for " + url, e);
+ throw new IllegalArgumentException("Cannot generate URL path for " + url, e);
}
}
node.setProperty(Property.JCR_HOST, u.getHost());
node.setProperty(Property.JCR_PORT, Integer.toString(u.getPort()));
node.setProperty(Property.JCR_PATH, normalizePath(u.getPath()));
- } catch (Exception e) {
- throw new ArgeoJcrException("Cannot set URL " + url + " as nt:address properties", e);
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot set URL " + url + " as nt:address properties", e);
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException("Cannot set URL " + url + " as nt:address properties", e);
}
}
(int) node.getProperty(Property.JCR_PORT).getLong(),
node.getProperty(Property.JCR_PATH).getString());
return u.toString();
- } catch (Exception e) {
- throw new ArgeoJcrException("Cannot get URL from nt:address properties of " + node, e);
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot get URL from nt:address properties of " + node, e);
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException("Cannot get URL from nt:address properties of " + node, e);
}
}
/**
* The provided data as a path ('/' at the end, not the beginning)
*
- * @param cal
- * the date
- * @param addHour
- * whether to add hour as well
+ * @param cal the date
+ * @param addHour whether to add hour as well
*/
public static String dateAsPath(Calendar cal, Boolean addHour) {
StringBuffer buf = new StringBuffer(14);
calendar.setTime(date);
return calendar;
} catch (ParseException e) {
- throw new ArgeoJcrException("Cannot parse " + value + " with date format " + dateFormat, e);
+ throw new IllegalArgumentException("Cannot parse " + value + " with date format " + dateFormat, e);
}
}
/** The last element of a path. */
public static String lastPathElement(String path) {
if (path.charAt(path.length() - 1) == '/')
- throw new ArgeoJcrException("Path " + path + " cannot end with '/'");
+ throw new IllegalArgumentException("Path " + path + " cannot end with '/'");
int index = path.lastIndexOf('/');
if (index < 0)
return path;
try {
return node.getName();
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot get name from " + node, e);
+ throw new JcrException("Cannot get name from " + node, e);
}
}
try {
return node.getProperty(propertyName).getString();
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot get name from " + node, e);
+ throw new JcrException("Cannot get name from " + node, e);
}
}
+// /**
+// * 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} */
return null;
return node.getProperty(propertyName).getString();
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot get property " + propertyName + " of " + node, e);
+ throw new JcrException("Cannot get property " + propertyName + " of " + node, e);
+ }
+ }
+
+ /** Concisely get the path of the given node. */
+ public static String getPath(Node node) {
+ try {
+ return node.getPath();
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot get path of " + node, e);
}
}
try {
return node.getProperty(propertyName).getBoolean();
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot get property " + propertyName + " of " + node, e);
+ throw new JcrException("Cannot get property " + propertyName + " of " + node, e);
}
}
try {
return getBinaryAsBytes(node.getProperty(propertyName));
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot get property " + propertyName + " of " + node, e);
+ throw new JcrException("Cannot get property " + propertyName + " of " + node, e);
}
}
/**
* Create sub nodes relative to a parent node
*
- * @param nodeType
- * the type of the leaf node
+ * @param nodeType the type of the leaf node
*/
public static Node mkdirs(Node parentNode, String relativePath, String nodeType) {
return mkdirs(parentNode, relativePath, nodeType, null);
/**
* Create sub nodes relative to a parent node
*
- * @param nodeType
- * the type of the leaf node
+ * @param nodeType the type of the leaf node
*/
public static Node mkdirs(Node parentNode, String relativePath, String nodeType, String intermediaryNodeType) {
List<String> tokens = tokenize(relativePath);
}
return currParent;
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot mkdirs relative path " + relativePath + " from " + parentNode, e);
+ throw new JcrException("Cannot mkdirs relative path " + relativePath + " from " + parentNode, e);
}
}
/**
- * Synchronized and save is performed, to avoid race conditions in
- * initializers leading to duplicate nodes.
+ * Synchronized and save is performed, to avoid race conditions in initializers
+ * leading to duplicate nodes.
*/
public synchronized static Node mkdirsSafe(Session session, String path, String type) {
try {
if (session.hasPendingChanges())
- throw new ArgeoJcrException("Session has pending changes, save them first.");
+ throw new IllegalStateException("Session has pending changes, save them first.");
Node node = mkdirs(session, path, type);
session.save();
return node;
} catch (RepositoryException e) {
discardQuietly(session);
- throw new ArgeoJcrException("Cannot safely make directories", e);
+ throw new JcrException("Cannot safely make directories", e);
}
}
}
/**
- * @param type
- * the type of the leaf node
+ * @param type the type of the leaf node
*/
public static Node mkdirs(Session session, String path, String type) {
return mkdirs(session, path, type, null, false);
}
/**
- * Creates the nodes making path, if they don't exist. This is up to the
- * caller to save the session. Use with caution since it can create
- * duplicate nodes if used concurrently. Requires read access to the root
- * node of the workspace.
+ * Creates the nodes making path, if they don't exist. This is up to the caller
+ * to save the session. Use with caution since it can create duplicate nodes if
+ * used concurrently. Requires read access to the root node of the workspace.
*/
public static Node mkdirs(Session session, String path, String type, String intermediaryNodeType,
Boolean versioning) {
try {
- if (path.equals('/'))
+ if (path.equals("/"))
return session.getRootNode();
if (session.itemExists(path)) {
Node node = session.getNode(path);
// check type
if (type != null && !node.isNodeType(type) && !node.getPath().equals("/"))
- throw new ArgeoJcrException("Node " + node + " exists but is of type "
+ throw new IllegalArgumentException("Node " + node + " exists but is of type "
+ node.getPrimaryNodeType().getName() + " not of type " + type);
// TODO: check versioning
return 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());
}
return currentNode;
} catch (RepositoryException e) {
discardQuietly(session);
- throw new ArgeoJcrException("Cannot mkdirs " + path, e);
+ throw new JcrException("Cannot mkdirs " + path, e);
} finally {
}
}
// }
/**
- * Safe and repository implementation independent registration of a
- * namespace.
+ * Safe and repository implementation independent registration of a namespace.
*/
public static void registerNamespaceSafely(Session session, String prefix, String uri) {
try {
registerNamespaceSafely(session.getWorkspace().getNamespaceRegistry(), prefix, uri);
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot find namespace registry", e);
+ throw new JcrException("Cannot find namespace registry", e);
}
}
/**
- * Safe and repository implementation independent registration of a
- * namespace.
+ * Safe and repository implementation independent registration of a namespace.
*/
public static void registerNamespaceSafely(NamespaceRegistry nr, String prefix, String uri) {
try {
if (pref.equals(prefix)) {
String registeredUri = nr.getURI(pref);
if (!registeredUri.equals(uri))
- throw new ArgeoJcrException("Prefix " + pref + " already registered for URI " + registeredUri
- + " which is different from provided URI " + uri);
+ throw new IllegalArgumentException("Prefix " + pref + " already registered for URI "
+ + registeredUri + " which is different from provided URI " + uri);
else
return;// skip
}
nr.registerNamespace(prefix, uri);
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot register namespace " + uri + " under prefix " + prefix, e);
+ throw new JcrException("Cannot register namespace " + uri + " under prefix " + prefix, e);
}
}
- /** 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;
-
- 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);
- }
- }
+// /** 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;
+//
+// 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) {
}
return buf.toString();
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot write summary of " + acl, e);
+ throw new JcrException("Cannot write summary of " + acl, e);
+ }
+ }
+
+ /** 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
* {@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.
+ * {@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 {
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) {
- throw new ArgeoJcrException("Cannot copy " + fromNode + " to " + toNode, e);
+ throw new JcrException("Cannot copy " + fromNode + " to " + toNode, e);
}
}
/**
- * Check whether all first-level properties (except jcr:* properties) are
- * equal. Skip jcr:* properties
+ * Check whether all first-level properties (except jcr:* properties) are equal.
+ * Skip jcr:* properties
*/
public static Boolean allPropertiesEquals(Node reference, Node observed, Boolean onlyCommonProperties) {
try {
}
return true;
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot check all properties equals of " + reference + " and " + observed, e);
+ throw new JcrException("Cannot check all properties equals of " + reference + " and " + observed, e);
}
}
}
/**
- * Compare the properties of two nodes. Recursivity to child nodes is not
- * yet supported. Skip jcr:* properties.
+ * Compare the properties of two nodes. Recursivity to child nodes is not yet
+ * supported. Skip jcr:* properties.
*/
static void diffPropertiesLevel(Map<String, PropertyDiff> diffs, String baseRelPath, Node reference,
Node observed) {
}
}
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot diff " + reference + " and " + observed, e);
+ throw new JcrException("Cannot diff " + reference + " and " + observed, e);
}
}
/**
- * Compare only a restricted list of properties of two nodes. No
- * recursivity.
+ * Compare only a restricted list of properties of two nodes. No recursivity.
*
*/
public static Map<String, PropertyDiff> diffProperties(Node reference, Node observed, List<String> properties) {
}
}
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot diff " + reference + " and " + observed, e);
+ throw new JcrException("Cannot diff " + reference + " and " + observed, e);
}
return diffs;
}
}
/**
- * Normalizes a name so that it can be stored in contexts not supporting
- * names with ':' (typically databases). Replaces ':' by '_'.
+ * Normalizes a name so that it can be stored in contexts not supporting names
+ * with ':' (typically databases). Replaces ':' by '_'.
*/
public static String normalize(String name) {
return name.replace(':', '_');
return name;
}
- /**
- * Removes forbidden characters from a path, replacing them with '_'
- *
- * @deprecated use {@link #replaceInvalidChars(String)} instead
- */
- public static String removeForbiddenCharacters(String str) {
- return str.replace('[', '_').replace(']', '_').replace('/', '_').replace('*', '_');
-
- }
+ // /**
+ // * Removes forbidden characters from a path, replacing them with '_'
+ // *
+ // * @deprecated use {@link #replaceInvalidChars(String)} instead
+ // */
+ // public static String removeForbiddenCharacters(String str) {
+ // return str.replace('[', '_').replace(']', '_').replace('/', '_').replace('*',
+ // '_');
+ //
+ // }
/** Cleanly disposes a {@link Binary} even if it is null. */
public static void closeQuietly(Binary binary) {
/** Retrieve a {@link Binary} as a byte array */
public static byte[] getBinaryAsBytes(Property property) {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- InputStream in = null;
- Binary binary = null;
- try {
- binary = property.getBinary();
- in = binary.getStream();
+ try (ByteArrayOutputStream out = new ByteArrayOutputStream();
+ Bin binary = new Bin(property);
+ InputStream in = binary.getStream()) {
IOUtils.copy(in, out);
return out.toByteArray();
- } catch (Exception e) {
- throw new ArgeoJcrException("Cannot read binary " + property + " as bytes", e);
- } finally {
- IOUtils.closeQuietly(out);
- IOUtils.closeQuietly(in);
- closeQuietly(binary);
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot read binary " + property + " as bytes", e);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot read binary " + property + " as bytes", e);
}
}
/** Writes a {@link Binary} from a byte array */
public static void setBinaryAsBytes(Node node, String property, byte[] bytes) {
- InputStream in = null;
Binary binary = null;
- try {
- in = new ByteArrayInputStream(bytes);
+ try (InputStream in = new ByteArrayInputStream(bytes)) {
binary = node.getSession().getValueFactory().createBinary(in);
node.setProperty(property, binary);
- } catch (Exception e) {
- throw new ArgeoJcrException("Cannot read binary " + property + " as bytes", e);
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot set binary " + property + " as bytes", e);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot set binary " + property + " as bytes", e);
+ } finally {
+ closeQuietly(binary);
+ }
+ }
+
+ /** Writes a {@link Binary} from a byte array */
+ public static void setBinaryAsBytes(Property prop, byte[] bytes) {
+ Binary binary = null;
+ try (InputStream in = new ByteArrayInputStream(bytes)) {
+ binary = prop.getSession().getValueFactory().createBinary(in);
+ prop.setValue(binary);
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot set binary " + prop + " as bytes", e);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot set binary " + prop + " as bytes", e);
} finally {
- IOUtils.closeQuietly(in);
closeQuietly(binary);
}
}
/**
- * Creates depth from a string (typically a username) by adding levels based
- * on its first characters: "aBcD",2 becomes a/aB
+ * Creates depth from a string (typically a username) by adding levels based on
+ * its first characters: "aBcD",2 becomes a/aB
*/
public static String firstCharsToPath(String str, Integer nbrOfChars) {
if (str.length() < nbrOfChars)
- throw new ArgeoJcrException("String " + str + " length must be greater or equal than " + nbrOfChars);
+ throw new IllegalArgumentException("String " + str + " length must be greater or equal than " + nbrOfChars);
StringBuffer path = new StringBuffer("");
StringBuffer curr = new StringBuffer("");
for (int i = 0; i < nbrOfChars; i++) {
}
/**
- * Discards the current changes in the session attached to this node. To be
- * used typically in a catch block.
+ * Discards the current changes in the session attached to this node. To be used
+ * typically in a catch block.
*
* @see #discardQuietly(Session)
*/
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
}
}
/**
- * Login to a workspace with implicit credentials, creates the workspace
- * with these credentials if it does not already exist.
+ * Login to a workspace with implicit credentials, creates the workspace with
+ * these credentials if it does not already exist.
*/
public static Session loginOrCreateWorkspace(Repository repository, String workspaceName)
throws RepositoryException {
+ return loginOrCreateWorkspace(repository, workspaceName, null);
+ }
+
+ /**
+ * Login to a workspace with implicit credentials, creates the workspace with
+ * these credentials if it does not already exist.
+ */
+ public static Session loginOrCreateWorkspace(Repository repository, String workspaceName, Credentials credentials)
+ throws RepositoryException {
Session workspaceSession = null;
Session defaultSession = null;
try {
try {
- workspaceSession = repository.login(workspaceName);
+ workspaceSession = repository.login(credentials, workspaceName);
} catch (NoSuchWorkspaceException e) {
// try to create workspace
- defaultSession = repository.login();
+ defaultSession = repository.login(credentials);
defaultSession.getWorkspace().createWorkspace(workspaceName);
- workspaceSession = repository.login(workspaceName);
+ workspaceSession = repository.login(credentials, workspaceName);
}
return workspaceSession;
} finally {
}
}
- /** Logs out the session, not throwing any exception, even if it is null. */
+ /**
+ * Logs out the session, not throwing any exception, even if it is null.
+ * {@link Jcr#logout(Session)} should rather be used.
+ */
public static void logoutQuietly(Session session) {
- try {
- if (session != null)
- if (session.isLive())
- session.logout();
- } catch (Exception e) {
- // silent
- }
+ Jcr.logout(session);
+// try {
+// if (session != null)
+// if (session.isLive())
+// session.logout();
+// } catch (Exception e) {
+// // silent
+// }
}
/**
session.getWorkspace().getObservationManager().addEventListener(listener, eventTypes, basePath, true, null,
nodeType == null ? null : new String[] { nodeType }, true);
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot add JCR listener " + listener + " to session " + session, e);
+ throw new JcrException("Cannot add JCR listener " + listener + " to session " + session, e);
}
}
}
/**
- * Quietly unregisters an {@link EventListener} from the udnerlying
- * workspace of this node.
+ * 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);
}
}
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.
+ * 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, 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());
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot update last modified on " + node, e);
+ throw new JcrException("Cannot update last modified on " + node, e);
}
}
/**
* Update lastModified recursively until this parent.
*
- * @param node
- * the node
- * @param untilPath
- * the base path, null is equivalent to "/"
+ * @param node the node
+ * @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 ArgeoJcrException(node + " is not under " + untilPath);
- updateLastModified(node);
+ throw new IllegalArgumentException(node + " is not under " + untilPath);
+ 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 ArgeoJcrException("Cannot update lastModified from " + node + " until " + untilPath, e);
+ throw new JcrException("Cannot update lastModified from " + node + " until " + untilPath, e);
}
}
if (prop.getDefinition().isMultiple())
sbuf.append("*");
} catch (RepositoryException re) {
- throw new ArgeoJcrException("unexpected error while getting property definition as String", re);
+ throw new JcrException("unexpected error while getting property definition as String", re);
}
return sbuf.toString();
}
/**
- * Estimate the sub tree size from current node. Computation is based on the
- * Jcr {@link Property#getLength()} method. Note : it is not the exact size
- * used on the disk by the current part of the JCR Tree.
+ * Estimate the sub tree size from current node. Computation is based on the Jcr
+ * {@link Property#getLength()} method. Note : it is not the exact size used on
+ * the disk by the current part of the JCR Tree.
*/
public static long getNodeApproxSize(Node node) {
curNodeSize += getNodeApproxSize(ni.nextNode());
return curNodeSize;
} catch (RepositoryException re) {
- throw new ArgeoJcrException("Unexpected error while recursively determining node size.", re);
+ throw new JcrException("Unexpected error while recursively determining node size.", re);
}
}
}
/**
- * Add privileges on a path to a {@link Principal}. The path must already
- * exist. Session is saved. Synchronized to prevent concurrent modifications
- * of the same node.
+ * Add privileges on a path to a {@link Principal}. The path must already exist.
+ * Session is saved. Synchronized to prevent concurrent modifications of the
+ * same node.
*/
public synchronized static Boolean addPrivileges(Session session, String path, Principal principal,
List<Privilege> privs) throws RepositoryException {
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;
}
- /** Gets access control list for this path, throws exception if not found */
+ /**
+ * Gets the first available access control list for this path, throws exception
+ * if not found
+ */
public synchronized static AccessControlList getAccessControlList(AccessControlManager acm, String path)
throws RepositoryException {
// search for an access control list
AccessControlList acl = null;
AccessControlPolicyIterator policyIterator = acm.getApplicablePolicies(path);
- if (policyIterator.hasNext()) {
+ applicablePolicies: if (policyIterator.hasNext()) {
while (policyIterator.hasNext()) {
AccessControlPolicy acp = policyIterator.nextAccessControlPolicy();
- if (acp instanceof AccessControlList)
+ if (acp instanceof AccessControlList) {
acl = ((AccessControlList) acp);
+ break applicablePolicies;
+ }
}
} else {
AccessControlPolicy[] existingPolicies = acm.getPolicies(path);
- for (AccessControlPolicy acp : existingPolicies) {
- if (acp instanceof AccessControlList)
+ existingPolicies: for (AccessControlPolicy acp : existingPolicies) {
+ if (acp instanceof AccessControlList) {
acl = ((AccessControlList) acp);
+ break existingPolicies;
+ }
}
}
if (acl != null)
return acl;
else
- throw new ArgeoJcrException("ACL not found at " + path);
+ throw new IllegalArgumentException("ACL not found at " + path);
}
/** Clear authorizations for a user at this path */
// the new access control list must be applied otherwise this call:
// acl.removeAccessControlEntry(ace); has no effect
acm.setPolicy(path, acl);
+ session.refresh(true);
+ session.save();
}
/*
* Copy only nt:folder and nt:file, without their additional types and
* properties.
*
- * @param recursive
- * if true copies folders as well, otherwise only first level
- * files
+ * @param recursive if true copies folders as well, otherwise only first level
+ * files
* @return how many files were copied
*/
- public static Long copyFiles(Node fromNode, Node toNode, Boolean recursive, JcrMonitor monitor) {
+ public static Long copyFiles(Node fromNode, Node toNode, Boolean recursive, JcrMonitor monitor, boolean onlyAdd) {
long count = 0l;
- Binary binary = null;
- InputStream in = null;
+ // Binary binary = null;
+ // InputStream in = null;
try {
NodeIterator fromChildren = fromNode.getNodes();
- while (fromChildren.hasNext()) {
+ children: while (fromChildren.hasNext()) {
if (monitor != null && monitor.isCanceled())
- throw new ArgeoJcrException("Copy cancelled before it was completed");
+ throw new IllegalStateException("Copy cancelled before it was completed");
Node fromChild = fromChildren.nextNode();
String fileName = fromChild.getName();
if (fromChild.isNodeType(NodeType.NT_FILE)) {
+ if (onlyAdd && toNode.hasNode(fileName)) {
+ monitor.subTask("Skip existing " + fileName);
+ continue children;
+ }
+
if (monitor != null)
monitor.subTask("Copy " + fileName);
- binary = fromChild.getNode(Node.JCR_CONTENT).getProperty(Property.JCR_DATA).getBinary();
- in = binary.getStream();
- copyStreamAsFile(toNode, fileName, in);
- IOUtils.closeQuietly(in);
- closeQuietly(binary);
+ try (Bin binary = new Bin(fromChild.getNode(Node.JCR_CONTENT).getProperty(Property.JCR_DATA));
+ InputStream in = binary.getStream();) {
+ copyStreamAsFile(toNode, fileName, in);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot copy " + fileName + " to " + toNode, e);
+ }
// save session
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) {
if (toNode.hasNode(fileName)) {
toChildFolder = toNode.getNode(fileName);
if (!toChildFolder.isNodeType(NodeType.NT_FOLDER))
- throw new ArgeoJcrException(toChildFolder + " is not of type nt:folder");
+ throw new IllegalArgumentException(toChildFolder + " is not of type nt:folder");
} else {
toChildFolder = toNode.addNode(fileName, NodeType.NT_FOLDER);
// save session
toNode.getSession().save();
}
- count = count + copyFiles(fromChild, toChildFolder, recursive, monitor);
+ count = count + copyFiles(fromChild, toChildFolder, recursive, monitor, onlyAdd);
}
}
return count;
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot copy files between " + fromNode + " and " + toNode);
+ throw new JcrException("Cannot copy files between " + fromNode + " and " + toNode, e);
} finally {
// in case there was an exception
- IOUtils.closeQuietly(in);
- closeQuietly(binary);
+ // IOUtils.closeQuietly(in);
+ // closeQuietly(binary);
}
}
/**
- * Iteratively count all file nodes in subtree, inefficient but can be
- * useful when query are poorly supported, such as in remoting.
+ * Iteratively count all file nodes in subtree, inefficient but can be useful
+ * when query are poorly supported, such as in remoting.
*/
public static Long countFiles(Node node) {
Long localCount = 0l;
localCount = localCount + 1;
}
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot count all children of " + node);
+ throw new JcrException("Cannot count all children of " + node, e);
}
return localCount;
}
/**
- * Copy a file as an nt:file, assuming an nt:folder hierarchy. The session
- * is NOT saved.
+ * Copy a file as an nt:file, assuming an nt:folder hierarchy. The session is
+ * NOT saved.
*
* @return the created file node
*/
+ @Deprecated
public static Node copyFile(Node folderNode, File file) {
- InputStream in = null;
- try {
- in = new FileInputStream(file);
+ try (InputStream in = new FileInputStream(file)) {
return copyStreamAsFile(folderNode, file.getName(), in);
} catch (IOException e) {
- throw new ArgeoJcrException("Cannot copy file " + file + " under " + folderNode, e);
- } finally {
- IOUtils.closeQuietly(in);
+ throw new RuntimeException("Cannot copy file " + file + " under " + folderNode, e);
}
}
/** Copy bytes as an nt:file */
public static Node copyBytesAsFile(Node folderNode, String fileName, byte[] bytes) {
- InputStream in = null;
- try {
- in = new ByteArrayInputStream(bytes);
+ // InputStream in = null;
+ try (InputStream in = new ByteArrayInputStream(bytes)) {
+ // in = new ByteArrayInputStream(bytes);
return copyStreamAsFile(folderNode, fileName, in);
- } catch (Exception e) {
- throw new ArgeoJcrException("Cannot copy file " + fileName + " under " + folderNode, e);
- } finally {
- IOUtils.closeQuietly(in);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot copy file " + fileName + " under " + folderNode, e);
+ // } finally {
+ // IOUtils.closeQuietly(in);
}
}
/**
- * Copy a stream as an nt:file, assuming an nt:folder hierarchy. The session
- * is NOT saved.
+ * Copy a stream as an nt:file, assuming an nt:folder hierarchy. The session is
+ * NOT saved.
*
* @return the created file node
*/
if (folderNode.hasNode(fileName)) {
fileNode = folderNode.getNode(fileName);
if (!fileNode.isNodeType(NodeType.NT_FILE))
- throw new ArgeoJcrException(fileNode + " is not of type nt:file");
+ throw new IllegalArgumentException(fileNode + " is not of type nt:file");
// we assume that the content node is already there
contentNode = fileNode.getNode(Node.JCR_CONTENT);
} else {
fileNode = folderNode.addNode(fileName, NodeType.NT_FILE);
- contentNode = fileNode.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE);
+ contentNode = fileNode.addNode(Node.JCR_CONTENT, NodeType.NT_UNSTRUCTURED);
}
binary = contentNode.getSession().getValueFactory().createBinary(in);
contentNode.setProperty(Property.JCR_DATA, binary);
+ updateLastModified(contentNode);
return fileNode;
- } catch (Exception e) {
- throw new ArgeoJcrException("Cannot create file node " + fileName + " under " + folderNode, e);
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot create file node " + fileName + " under " + folderNode, e);
} finally {
closeQuietly(binary);
}
}
- /** Computes the checksum of an nt:file */
- public static String checksumFile(Node fileNode, String algorithm) {
- Binary data = null;
- InputStream in = null;
+ /** Read an an nt:file as an {@link InputStream}. */
+ public static InputStream getFileAsStream(Node fileNode) throws RepositoryException {
+ return fileNode.getNode(Node.JCR_CONTENT).getProperty(Property.JCR_DATA).getBinary().getStream();
+ }
+
+ /**
+ * Set the properties of {@link NodeType#MIX_MIMETYPE} on the content of this
+ * file node.
+ */
+ public static void setFileMimeType(Node fileNode, String mimeType, String encoding) throws RepositoryException {
+ Node contentNode = fileNode.getNode(Node.JCR_CONTENT);
+ if (mimeType != null)
+ contentNode.setProperty(Property.JCR_MIMETYPE, mimeType);
+ if (encoding != null)
+ contentNode.setProperty(Property.JCR_ENCODING, encoding);
+ // TODO remove properties if args are null?
+ }
+
+ public static void copyFilesToFs(Node baseNode, Path targetDir, boolean recursive) {
try {
- data = fileNode.getNode(Node.JCR_CONTENT).getProperty(Property.JCR_DATA).getBinary();
- in = data.getStream();
- return DigestUtils.digest(algorithm, in);
+ Files.createDirectories(targetDir);
+ for (NodeIterator nit = baseNode.getNodes(); nit.hasNext();) {
+ Node node = nit.nextNode();
+ if (node.isNodeType(NodeType.NT_FILE)) {
+ Path filePath = targetDir.resolve(node.getName());
+ try (OutputStream out = Files.newOutputStream(filePath); InputStream in = getFileAsStream(node)) {
+ IOUtils.copy(in, out);
+ }
+ } else if (recursive && node.isNodeType(NodeType.NT_FOLDER)) {
+ Path dirPath = targetDir.resolve(node.getName());
+ copyFilesToFs(node, dirPath, true);
+ }
+ }
} catch (RepositoryException e) {
- throw new ArgeoJcrException("Cannot checksum file " + fileNode, e);
- } finally {
- IOUtils.closeQuietly(in);
- closeQuietly(data);
+ throw new JcrException("Cannot copy " + baseNode + " to " + targetDir, e);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot copy " + baseNode + " to " + targetDir, e);
+ }
+ }
+
+ /**
+ * Computes the checksum of an nt:file.
+ *
+ * @deprecated use separate digest utilities
+ */
+ @Deprecated
+ public static String checksumFile(Node fileNode, String algorithm) {
+ try (InputStream in = fileNode.getNode(Node.JCR_CONTENT).getProperty(Property.JCR_DATA).getBinary()
+ .getStream()) {
+ return digest(algorithm, in);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot checksum file " + fileNode + " with algorithm " + algorithm, e);
+ } catch (RepositoryException e) {
+ throw new JcrException("Cannot checksum file " + fileNode + " with algorithm " + algorithm, e);
+ }
+ }
+
+ @Deprecated
+ private static String digest(String algorithm, InputStream in) {
+ final Integer byteBufferCapacity = 100 * 1024;// 100 KB
+ try {
+ MessageDigest digest = MessageDigest.getInstance(algorithm);
+ byte[] buffer = new byte[byteBufferCapacity];
+ int read = 0;
+ while ((read = in.read(buffer)) > 0) {
+ digest.update(buffer, 0, read);
+ }
+
+ byte[] checksum = digest.digest();
+ String res = encodeHexString(checksum);
+ return res;
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot digest with algorithm " + algorithm, e);
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalArgumentException("Cannot digest with algorithm " + algorithm, e);
+ }
+ }
+
+ /**
+ * From
+ * http://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to
+ * -a-hex-string-in-java
+ */
+ @Deprecated
+ private static String encodeHexString(byte[] bytes) {
+ final char[] hexArray = "0123456789abcdef".toCharArray();
+ char[] hexChars = new char[bytes.length * 2];
+ for (int j = 0; j < bytes.length; j++) {
+ int v = bytes[j] & 0xFF;
+ hexChars[j * 2] = hexArray[v >>> 4];
+ hexChars[j * 2 + 1] = hexArray[v & 0x0F];
+ }
+ return new String(hexChars);
+ }
+
+ /** Export a subtree as a compact XML without namespaces. */
+ public static void toSimpleXml(Node node, StringBuilder sb) throws RepositoryException {
+ sb.append('<');
+ String nodeName = node.getName();
+ int colIndex = nodeName.indexOf(':');
+ if (colIndex > 0) {
+ nodeName = nodeName.substring(colIndex + 1);
+ }
+ sb.append(nodeName);
+ PropertyIterator pit = node.getProperties();
+ properties: while (pit.hasNext()) {
+ Property p = pit.nextProperty();
+ // skip multiple properties
+ if (p.isMultiple())
+ continue properties;
+ String propertyName = p.getName();
+ int pcolIndex = propertyName.indexOf(':');
+ // skip properties with namespaces
+ if (pcolIndex > 0)
+ continue properties;
+ // skip binaries
+ if (p.getType() == PropertyType.BINARY) {
+ continue properties;
+ // TODO retrieve identifier?
+ }
+ sb.append(' ');
+ sb.append(propertyName);
+ sb.append('=');
+ sb.append('\"').append(p.getString()).append('\"');
+ }
+
+ if (node.hasNodes()) {
+ sb.append('>');
+ NodeIterator children = node.getNodes();
+ while (children.hasNext()) {
+ toSimpleXml(children.nextNode(), sb);
+ }
+ sb.append("</");
+ sb.append(nodeName);
+ sb.append('>');
+ } else {
+ sb.append("/>");
}
}