X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.jcr%2Fsrc%2Forg%2Fargeo%2Fjcr%2FJcr.java;h=72e325d35a40c40ad22a712ae7561fd33ae6ed87;hb=98ff62f2df01366777fda9b4dbe7586b0cd45252;hp=4b8bfc3eae5761bcfd3d04f8cd188706ba99c242;hpb=4f6cfbd6862813e917883ea93e13ee95edc1c024;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.jcr/src/org/argeo/jcr/Jcr.java b/org.argeo.jcr/src/org/argeo/jcr/Jcr.java index 4b8bfc3ea..72e325d35 100644 --- a/org.argeo.jcr/src/org/argeo/jcr/Jcr.java +++ b/org.argeo.jcr/src/org/argeo/jcr/Jcr.java @@ -1,5 +1,8 @@ package org.argeo.jcr; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.math.BigDecimal; import java.text.MessageFormat; import java.time.Instant; @@ -32,6 +35,8 @@ import javax.jcr.version.VersionHistory; import javax.jcr.version.VersionIterator; import javax.jcr.version.VersionManager; +import org.apache.commons.io.IOUtils; + /** * Utility class whose purpose is to make using JCR less verbose by * systematically using unchecked exceptions and returning null @@ -132,6 +137,14 @@ public class Jcr { } } + /** + * @see Node#getParent() + * @throws JcrException caused by {@link RepositoryException} + */ + public static String getParentPath(Node node) { + return getPath(getParent(node)); + } + /** * Whether this node is the root node. * @@ -190,6 +203,48 @@ public class Jcr { } } + /** + * Returns the node name with its current index (useful for re-ordering). + * + * @see Node#getName() + * @see Node#getIndex() + * @throws JcrException caused by {@link RepositoryException} + */ + public static String getIndexedName(Node node) { + try { + return node.getName() + "[" + node.getIndex() + "]"; + } catch (RepositoryException e) { + throw new JcrException("Cannot get name of " + node, e); + } + } + + /** + * @see Node#getProperty(String) + * @throws JcrException caused by {@link RepositoryException} + */ + public static Property getProperty(Node node, String property) { + try { + if (node.hasProperty(property)) + return node.getProperty(property); + else + return null; + } catch (RepositoryException e) { + throw new JcrException("Cannot get property " + property + " of " + node, e); + } + } + + /** + * @see Node#getIndex() + * @throws JcrException caused by {@link RepositoryException} + */ + public static int getIndex(Node node) { + try { + return node.getIndex(); + } catch (RepositoryException e) { + throw new JcrException("Cannot get index of " + node, e); + } + } + /** * If node has mixin {@link NodeType#MIX_TITLE}, return * {@link Property#JCR_TITLE}, otherwise return {@link #getName(Node)}. @@ -381,11 +436,19 @@ public class Jcr { public static void set(Node node, String property, Object value) { try { if (!node.hasProperty(property)) { - if (value != null) - node.setProperty(property, value.toString()); + if (value != null) { + if (value instanceof List) {// multiple + List lst = (List) value; + String[] values = new String[lst.size()]; + for (int i = 0; i < lst.size(); i++) { + values[i] = lst.get(i).toString(); + } + node.setProperty(property, values); + } else { + node.setProperty(property, value.toString()); + } + } return; - // throw new IllegalArgumentException("No property " + property + " in " + - // node); } Property prop = node.getProperty(property); if (value == null) { @@ -393,6 +456,27 @@ public class Jcr { return; } + // multiple + if (value instanceof List) { + List lst = (List) value; + String[] values = new String[lst.size()]; + // TODO better cast? + for (int i = 0; i < lst.size(); i++) { + values[i] = lst.get(i).toString(); + } + if (!prop.isMultiple()) + prop.remove(); + node.setProperty(property, values); + return; + } + + // single + if (prop.isMultiple()) { + prop.remove(); + node.setProperty(property, value.toString()); + return; + } + if (value instanceof String) prop.setValue((String) value); else if (value instanceof Long) @@ -498,20 +582,11 @@ public class Jcr { if (node.hasProperty(property)) { Property p = node.getProperty(property); try { - switch (p.getType()) { - case PropertyType.STRING: - return (T) node.getProperty(property).getString(); - case PropertyType.DOUBLE: - return (T) (Double) node.getProperty(property).getDouble(); - case PropertyType.LONG: - return (T) (Long) node.getProperty(property).getLong(); - case PropertyType.BOOLEAN: - return (T) (Boolean) node.getProperty(property).getBoolean(); - case PropertyType.DATE: - return (T) node.getProperty(property).getDate(); - default: - return (T) node.getProperty(property).getString(); + if (p.isMultiple()) { + throw new UnsupportedOperationException("Multiple values properties are not supported"); } + Value value = p.getValue(); + return (T) get(value); } catch (ClassCastException e) { throw new IllegalArgumentException( "Cannot cast property of type " + PropertyType.nameFromValue(p.getType()), e); @@ -524,6 +599,86 @@ public class Jcr { } } + /** + * Get a multiple property as a list, doing a best effort to cast it as the + * target list. + * + * @return the value of {@link Node#getProperty(String)}. + * @throws IllegalArgumentException if the value could not be cast + * @throws JcrException in case of unexpected + * {@link RepositoryException} + */ + public static List getMultiple(Node node, String property) { + try { + if (node.hasProperty(property)) { + Property p = node.getProperty(property); + return getMultiple(p); + } else { + return null; + } + } catch (RepositoryException e) { + throw new JcrException("Cannot retrieve multiple values property " + property + " from " + node, e); + } + } + + /** + * Get a multiple property as a list, doing a best effort to cast it as the + * target list. + */ + @SuppressWarnings("unchecked") + public static List getMultiple(Property p) { + try { + List res = new ArrayList<>(); + if (!p.isMultiple()) { + res.add((T) get(p.getValue())); + return res; + } + Value[] values = p.getValues(); + for (Value value : values) { + res.add((T) get(value)); + } + return res; + } catch (ClassCastException | RepositoryException e) { + throw new IllegalArgumentException("Cannot get property " + p, e); + } + } + + /** Cast a {@link Value} to a standard Java object. */ + public static Object get(Value value) { + Binary binary = null; + try { + switch (value.getType()) { + case PropertyType.STRING: + return value.getString(); + case PropertyType.DOUBLE: + return (Double) value.getDouble(); + case PropertyType.LONG: + return (Long) value.getLong(); + case PropertyType.BOOLEAN: + return (Boolean) value.getBoolean(); + case PropertyType.DATE: + return value.getDate(); + case PropertyType.BINARY: + binary = value.getBinary(); + byte[] arr = null; + try (InputStream in = binary.getStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();) { + IOUtils.copy(in, out); + arr = out.toByteArray(); + } catch (IOException e) { + throw new RuntimeException("Cannot read binary from " + value, e); + } + return arr; + default: + return value.getString(); + } + } catch (RepositoryException e) { + throw new JcrException("Cannot cast value from " + value, e); + } finally { + if (binary != null) + binary.dispose(); + } + } + /** * Retrieves the {@link Session} related to this node. * @@ -747,6 +902,8 @@ public class Jcr { // QUERY /** Creates a JCR-SQL2 query using {@link MessageFormat}. */ public static Query createQuery(QueryManager qm, String sql, Object... args) { + // fix single quotes + sql = sql.replaceAll("'", "''"); String query = MessageFormat.format(sql, args); try { return qm.createQuery(query, Query.JCR_SQL2);