]> git.argeo.org Git - lgpl/argeo-commons.git/blobdiff - server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java
Improve JCR
[lgpl/argeo-commons.git] / server / runtime / org.argeo.server.jcr / src / main / java / org / argeo / jcr / JcrUtils.java
index 1cecd7100611744524da8e08296dbc49f00b935a..eeaff3a924f505cee38124e3ac85a090dbc5295e 100644 (file)
@@ -16,6 +16,9 @@
 
 package org.argeo.jcr;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.text.DateFormat;
@@ -36,6 +39,7 @@ 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.RepositoryFactory;
@@ -52,6 +56,7 @@ import javax.jcr.query.qom.QueryObjectModelFactory;
 import javax.jcr.query.qom.Selector;
 import javax.jcr.query.qom.StaticOperand;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.ArgeoException;
@@ -219,14 +224,35 @@ public class JcrUtils implements ArgeoJcrConstants {
                return path.substring(index + 1);
        }
 
+       /**
+        * Routine that get the child with this name, adding id 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);
+       }
+
+       /**
+        * Routine that get the child with this name, adding id 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);
+       }
+
        /** Creates the nodes making path, if they don't exist. */
        public static Node mkdirs(Session session, String path) {
                return mkdirs(session, path, null, null, false);
        }
 
        /**
-        * @deprecated use {@link #mkdirs(Session, String, String, String, Boolean)}
-        *             instead.
+        * use {@link #mkdirs(Session, String, String, String, Boolean)} instead.
+        * 
+        * @deprecated
         */
        @Deprecated
        public static Node mkdirs(Session session, String path, String type,
@@ -354,15 +380,17 @@ public class JcrUtils implements ArgeoJcrConstants {
                        NodeIterator it = node.getNodes();
                        while (it.hasNext()) {
                                Node childNode = it.nextNode();
-                               debug(childNode);
+                               debug(childNode, log);
                        }
 
                        // Then output the properties
                        PropertyIterator properties = node.getProperties();
                        // log.debug("Property are : ");
 
-                       while (properties.hasNext()) {
+                       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();
@@ -659,6 +687,43 @@ public class JcrUtils implements ArgeoJcrConstants {
                binary.dispose();
        }
 
+       /** 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();
+                       IOUtils.copy(in, out);
+                       return out.toByteArray();
+               } catch (Exception e) {
+                       throw new ArgeoException("Cannot read binary " + property
+                                       + " as bytes", e);
+               } finally {
+                       IOUtils.closeQuietly(out);
+                       IOUtils.closeQuietly(in);
+                       closeQuietly(binary);
+               }
+       }
+
+       /** 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);
+                       binary = node.getSession().getValueFactory().createBinary(in);
+                       node.setProperty(property, binary);
+               } catch (Exception e) {
+                       throw new ArgeoException("Cannot read binary " + property
+                                       + " 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 => a/aB
@@ -847,15 +912,35 @@ public class JcrUtils implements ArgeoJcrConstants {
                        if (session.hasPendingChanges())
                                throw new ArgeoException(
                                                "Session has pending changes, save them first");
+
                        String homePath = homeBasePath + '/'
                                        + firstCharsToPath(username, 2) + '/' + username;
-                       Node userHome = JcrUtils.mkdirs(session, homePath);
 
-                       Node userProfile = userHome.addNode(ArgeoNames.ARGEO_PROFILE);
-                       userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE);
-                       userProfile.setProperty(ArgeoNames.ARGEO_USER_ID, username);
-                       session.save();
-                       // we need to save the profile before adding the user home type
+                       if (session.itemExists(homePath)) {
+                               try {
+                                       throw new ArgeoException(
+                                                       "Trying to create a user home that already exists");
+                               } catch (Exception e) {
+                                       // we use this workaround to be sure to get the stack trace
+                                       // to identify the sink of the bug.
+                                       log.warn("trying to create an already existing userHome at path:"
+                                                       + homePath + ". Stack trace : ");
+                                       e.printStackTrace();
+                               }
+                       }
+
+                       Node userHome = JcrUtils.mkdirs(session, homePath);
+                       Node userProfile;
+                       if (userHome.hasNode(ArgeoNames.ARGEO_PROFILE)) {
+                               log.warn("userProfile node already exists for userHome path: "
+                                               + homePath + ". We do not add a new one");
+                       } else {
+                               userProfile = userHome.addNode(ArgeoNames.ARGEO_PROFILE);
+                               userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE);
+                               userProfile.setProperty(ArgeoNames.ARGEO_USER_ID, username);
+                               session.save();
+                               // we need to save the profile before adding the user home type
+                       }
                        userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
                        // see
                        // http://jackrabbit.510166.n4.nabble.com/Jackrabbit-2-0-beta-6-Problem-adding-a-Mixin-type-with-mandatory-properties-after-setting-propertiesn-td1290332.html
@@ -921,4 +1006,64 @@ public class JcrUtils implements ArgeoJcrConstants {
                        throw new ArgeoException("Cannot update last modified", e);
                }
        }
+
+       /**
+        * Returns a String representing the short version (see <a
+        * href="http://jackrabbit.apache.org/node-type-notation.html"> Node type
+        * Notation </a> attributes grammar) of the main business attributes of this
+        * property definition
+        * 
+        * @param prop
+        */
+       public static String getPropertyDefinitionAsString(Property prop) {
+               StringBuffer sbuf = new StringBuffer();
+               try {
+                       if (prop.getDefinition().isAutoCreated())
+                               sbuf.append("a");
+                       if (prop.getDefinition().isMandatory())
+                               sbuf.append("m");
+                       if (prop.getDefinition().isProtected())
+                               sbuf.append("p");
+                       if (prop.getDefinition().isMultiple())
+                               sbuf.append("*");
+               } catch (RepositoryException re) {
+                       throw new ArgeoException(
+                                       "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.
+        */
+
+       public static long getNodeApproxSize(Node node) {
+               long curNodeSize = 0;
+               try {
+                       PropertyIterator pi = node.getProperties();
+                       while (pi.hasNext()) {
+                               Property prop = pi.nextProperty();
+                               if (prop.isMultiple()) {
+                                       int nb = prop.getLengths().length;
+                                       for (int i = 0; i < nb; i++) {
+                                               curNodeSize += (prop.getLengths()[i] > 0 ? prop
+                                                               .getLengths()[i] : 0);
+                                       }
+                               } else
+                                       curNodeSize += (prop.getLength() > 0 ? prop.getLength() : 0);
+                       }
+
+                       NodeIterator ni = node.getNodes();
+                       while (ni.hasNext())
+                               curNodeSize += getNodeApproxSize(ni.nextNode());
+                       return curNodeSize;
+               } catch (RepositoryException re) {
+                       throw new ArgeoException(
+                                       "Unexpected error while recursively determining node size.",
+                                       re);
+               }
+       }
 }