From: Mathieu Baudier Date: Sat, 31 Oct 2020 08:50:52 +0000 (+0100) Subject: Introduce JCR XML utilities. X-Git-Tag: argeo-commons-2.1.89~46 X-Git-Url: https://git.argeo.org/?p=lgpl%2Fargeo-commons.git;a=commitdiff_plain;h=8e5934c1ff5587a5156854839210cc93bb66fc41 Introduce JCR XML utilities. --- diff --git a/org.argeo.jcr/build.properties b/org.argeo.jcr/build.properties index 8a9736e84..027445903 100644 --- a/org.argeo.jcr/build.properties +++ b/org.argeo.jcr/build.properties @@ -12,7 +12,6 @@ additional.bundles = org.junit,\ org.apache.jackrabbit.spi,\ org.apache.jackrabbit.spi.commons,\ org.slf4j.api,\ - org.slf4j.commons.logging,\ org.slf4j.log4j12,\ org.apache.log4j,\ org.apache.commons.collections,\ diff --git a/org.argeo.jcr/src/org/argeo/jcr/Jcr.java b/org.argeo.jcr/src/org/argeo/jcr/Jcr.java index fb6f61013..5ce8017ca 100644 --- a/org.argeo.jcr/src/org/argeo/jcr/Jcr.java +++ b/org.argeo.jcr/src/org/argeo/jcr/Jcr.java @@ -36,6 +36,55 @@ import javax.jcr.version.VersionManager; * exceptions. Loosely inspired by Java's Files singleton. */ public class Jcr { + + /** + * jcr:name, when used in another context than + * {@link Property#JCR_NAME}, typically to name a node rather than a property. + */ + public final static String JCR_NAME = "jcr:name"; + + /** + * jcr:path, when used in another context than + * {@link Property#JCR_PATH}, typically to name a node rather than a property. + */ + public final static String JCR_PATH = "jcr:path"; + + /** + * jcr:primaryType with prefix instead of namespace (as in + * {@link Property#JCR_PRIMARY_TYPE}. + */ + public final static String JCR_PRIMARY_TYPE = "jcr:primaryType"; + /** + * jcr:mixinTypes with prefix instead of namespace (as in + * {@link Property#JCR_MIXIN_TYPES}. + */ + public final static String JCR_MIXIN_TYPES = "jcr:mixinTypes"; + /** + * jcr:uuid with prefix instead of namespace (as in + * {@link Property#JCR_UUID}. + */ + public final static String JCR_UUID = "jcr:uuid"; + /** + * jcr:created with prefix instead of namespace (as in + * {@link Property#JCR_CREATED}. + */ + public final static String JCR_CREATED = "jcr:created"; + /** + * jcr:createdBy with prefix instead of namespace (as in + * {@link Property#JCR_CREATED_BY}. + */ + public final static String JCR_CREATED_BY = "jcr:createdBy"; + /** + * jcr:lastModified with prefix instead of namespace (as in + * {@link Property#JCR_LAST_MODIFIED}. + */ + public final static String JCR_LAST_MODIFIED = "jcr:lastModified"; + /** + * jcr:lastModifiedBy with prefix instead of namespace (as in + * {@link Property#JCR_LAST_MODIFIED_BY}. + */ + public final static String JCR_LAST_MODIFIED_BY = "jcr:lastModifiedBy"; + /** * @see Node#isNodeType(String) * @throws IllegalStateException caused by {@link RepositoryException} diff --git a/org.argeo.jcr/src/org/argeo/jcr/JcrUtils.java b/org.argeo.jcr/src/org/argeo/jcr/JcrUtils.java index 857bd60b0..e304649e2 100644 --- a/org.argeo.jcr/src/org/argeo/jcr/JcrUtils.java +++ b/org.argeo.jcr/src/org/argeo/jcr/JcrUtils.java @@ -31,7 +31,6 @@ 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; @@ -49,13 +48,11 @@ import javax.jcr.security.AccessControlPolicyIterator; 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 @@ -500,8 +497,8 @@ public class JcrUtils { 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()); } @@ -601,83 +598,83 @@ public class JcrUtils { } } - /** 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) { @@ -1031,7 +1028,7 @@ public class JcrUtils { try { discardQuietly(node.getSession()); } catch (RepositoryException e) { - log.warn("Cannot quietly discard session of node " + node + ": " + e.getMessage()); + // silent } } @@ -1045,7 +1042,7 @@ public class JcrUtils { if (session != null) session.refresh(false); } catch (RepositoryException e) { - log.warn("Cannot quietly discard session " + session + ": " + e.getMessage()); + // silent } } @@ -1130,8 +1127,6 @@ public class JcrUtils { unregisterQuietly(node.getSession().getWorkspace(), eventListener); } catch (RepositoryException e) { // silent - if (log.isTraceEnabled()) - log.trace("Could not unregister event listener " + eventListener); } } @@ -1143,8 +1138,6 @@ public class JcrUtils { workspace.getObservationManager().removeEventListener(eventListener); } catch (RepositoryException e) { // silent - if (log.isTraceEnabled()) - log.trace("Could not unregister event listener " + eventListener); } } @@ -1293,13 +1286,13 @@ public class JcrUtils { 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; @@ -1402,8 +1395,8 @@ public class JcrUtils { 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) { diff --git a/org.argeo.jcr/src/org/argeo/jcr/xml/JcrXmlUtils.java b/org.argeo.jcr/src/org/argeo/jcr/xml/JcrXmlUtils.java new file mode 100644 index 000000000..6f1a92260 --- /dev/null +++ b/org.argeo.jcr/src/org/argeo/jcr/xml/JcrXmlUtils.java @@ -0,0 +1,126 @@ +package org.argeo.jcr.xml; + +import java.io.IOException; +import java.io.Writer; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Property; +import javax.jcr.PropertyIterator; +import javax.jcr.RepositoryException; +import javax.jcr.Value; +import javax.jcr.nodetype.NodeType; + +import org.argeo.jcr.Jcr; + +/** Utilities around JCR and XML. */ +public class JcrXmlUtils { + /** + * Convenience method calling {@link #toXmlElements(Writer, Node, boolean)} with + * false. + */ + public static void toXmlElements(Writer writer, Node node) throws RepositoryException, IOException { + toXmlElements(writer, node, false, false); + } + + /** + * Write JCR properties as XML elements in a tree structure whose elements are + * named by node primary type. + * + * @param writer the writer to use + * @param node the subtree + * @param withMetadata whether to write the primary type and mixins as elements + * jcr:primaryType ( + */ + public static void toXmlElements(Writer writer, Node node, boolean withMetadata, boolean withPrefix) + throws RepositoryException, IOException { + if (withMetadata && node.hasProperty(Property.JCR_UUID)) { + writeStart(writer, withPrefix(node.getPrimaryNodeType().getName(), withPrefix), "id", + "urn:uuid:" + node.getProperty(Property.JCR_UUID).getString()); + } else { + writeStart(writer, withPrefix(node.getPrimaryNodeType().getName(), withPrefix)); + } + + // name + writeStart(writer, withPrefix ? Jcr.JCR_NAME : "name"); + writer.append(node.getName()); + writeEnd(writer, withPrefix ? Jcr.JCR_NAME : "name"); + + // mixins + if (withMetadata) { + for (NodeType mixin : node.getMixinNodeTypes()) { + writeStart(writer, withPrefix ? Jcr.JCR_MIXIN_TYPES : "mixinTypes"); + writer.append(mixin.getName()); + writeEnd(writer, withPrefix ? Jcr.JCR_MIXIN_TYPES : "mixinTypes"); + } + } + + // properties + PropertyIterator pit = node.getProperties(); + properties: while (pit.hasNext()) { + Property p = pit.nextProperty(); + if (p.isMultiple()) { + for (Value value : p.getValues()) { + writeStart(writer, withPrefix(p.getName(), withPrefix)); + writer.write(value.getString()); + writeEnd(writer, withPrefix(p.getName(), withPrefix)); + } + } else { + Value value = p.getValue(); + String pName = p.getName(); + if (!withMetadata && (pName.equals(Jcr.JCR_PRIMARY_TYPE) || pName.equals(Jcr.JCR_UUID) + || pName.equals(Jcr.JCR_CREATED) || pName.equals(Jcr.JCR_CREATED_BY) + || pName.equals(Jcr.JCR_LAST_MODIFIED) || pName.equals(Jcr.JCR_LAST_MODIFIED_BY))) + continue properties; + writeStart(writer, withPrefix(p.getName(), withPrefix)); + writer.write(value.getString()); + writeEnd(writer, withPrefix(p.getName(), withPrefix)); + } + } + + // children + NodeIterator nit = node.getNodes(); + while (nit.hasNext()) { + toXmlElements(writer, nit.nextNode(), withMetadata, withPrefix); + } + + writeEnd(writer, withPrefix(node.getPrimaryNodeType().getName(), withPrefix)); + } + + private static String withPrefix(String str, boolean withPrefix) { + if (withPrefix) + return str; + int index = str.indexOf(':'); + if (index < 0) + return str; + return str.substring(index + 1); + } + + private static void writeStart(Writer writer, String tagName) throws IOException { + writer.append('<'); + writer.append(tagName); + writer.append('>'); + } + + private static void writeStart(Writer writer, String tagName, String attr, String value) throws IOException { + writer.append('<'); + writer.append(tagName); + writer.append(' '); + writer.append(attr); + writer.append("=\""); + writer.append(value); + writer.append("\">"); + } + + private static void writeEnd(Writer writer, String tagName) throws IOException { + writer.append("'); + } + + /** Singleton. */ + private JcrXmlUtils() { + + } + +}