X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=server%2Fruntime%2Forg.argeo.server.jcr%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fjcr%2FJcrUtils.java;h=facd475cafd1e789c1689e7f88e317ff1ec1d749;hb=8b8ee149b20e2578a55e17413fa5f7399ff7ba14;hp=760e6600969e9e5666468e47afe1cd230be7bc1b;hpb=78469faf92044c7ad7b3a829ae2b5e4f943748b7;p=lgpl%2Fargeo-commons.git diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java index 760e66009..facd475ca 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java @@ -23,14 +23,15 @@ import java.net.MalformedURLException; import java.net.URL; import java.text.DateFormat; import java.text.ParseException; +import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.StringTokenizer; import java.util.TreeMap; import javax.jcr.Binary; @@ -39,6 +40,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; @@ -143,6 +145,46 @@ public class JcrUtils implements ArgeoJcrConstants { } } + /** Set the {@link NodeType#NT_ADDRESS} properties based on this URL. */ + public static void urlToAddressProperties(Node node, String url) { + try { + URL u = new URL(url); + node.setProperty(Property.JCR_PROTOCOL, u.getProtocol()); + 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 ArgeoException("Cannot set URL " + url + + " as nt:address properties", e); + } + } + + /** Build URL based on the {@link NodeType#NT_ADDRESS} properties. */ + public static String urlFromAddressProperties(Node node) { + try { + URL u = new URL( + node.getProperty(Property.JCR_PROTOCOL).getString(), node + .getProperty(Property.JCR_HOST).getString(), + (int) node.getProperty(Property.JCR_PORT).getLong(), node + .getProperty(Property.JCR_PATH).getString()); + return u.toString(); + } catch (Exception e) { + throw new ArgeoException( + "Cannot get URL from nt:address properties of " + node, e); + } + } + + /** Make sure that: starts with '/', do not end with '/', do not have '//' */ + public static String normalizePath(String path) { + List tokens = tokenize(path); + StringBuffer buf = new StringBuffer(path.length()); + for (String token : tokens) { + buf.append('/'); + buf.append(token); + } + return buf.toString(); + } + /** * Creates a path from a FQDN, inverting the order of the component: * www.argeo.org => org.argeo.www @@ -223,6 +265,26 @@ 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); @@ -247,9 +309,33 @@ public class JcrUtils implements ArgeoJcrConstants { return mkdirs(session, path, type, null, false); } + /** + * 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 ArgeoException( + "Session has pending changes, save them first."); + Node node = mkdirs(session, path, type); + session.save(); + return node; + } catch (RepositoryException e) { + discardQuietly(session); + throw new ArgeoException("Cannot safely make directories", e); + } + } + + public synchronized static Node mkdirsSafe(Session session, String path) { + return mkdirsSafe(session, path, null); + } + /** * Creates the nodes making path, if they don't exist. This is up to the - * caller to save the session. + * caller to save the session. Use with caution since it can create + * duplicate nodes if used concurrently. */ public static Node mkdirs(Session session, String path, String type, String intermediaryNodeType, Boolean versioning) { @@ -270,16 +356,16 @@ public class JcrUtils implements ArgeoJcrConstants { return node; } - StringTokenizer st = new StringTokenizer(path, "/"); StringBuffer current = new StringBuffer("/"); Node currentNode = session.getRootNode(); - while (st.hasMoreTokens()) { - String part = st.nextToken(); + Iterator it = tokenize(path).iterator(); + while (it.hasNext()) { + String part = it.next(); current.append(part).append('/'); if (!session.itemExists(current.toString())) { - if (!st.hasMoreTokens() && type != null) + if (!it.hasNext() && type != null) currentNode = currentNode.addNode(part, type); - else if (st.hasMoreTokens() && intermediaryNodeType != null) + else if (it.hasNext() && intermediaryNodeType != null) currentNode = currentNode.addNode(part, intermediaryNodeType); else @@ -292,11 +378,45 @@ public class JcrUtils implements ArgeoJcrConstants { currentNode = (Node) session.getItem(current.toString()); } } - // session.save(); return currentNode; } catch (RepositoryException e) { + discardQuietly(session); throw new ArgeoException("Cannot mkdirs " + path, e); + } finally { + } + } + + /** Convert a path to the list of its tokens */ + public static List tokenize(String path) { + List tokens = new ArrayList(); + boolean optimized = false; + if (!optimized) { + String[] rawTokens = path.split("/"); + for (String token : rawTokens) { + if (!token.equals("")) + tokens.add(token); + } + } else { + StringBuffer curr = new StringBuffer(); + char[] arr = path.toCharArray(); + chars: for (int i = 0; i < arr.length; i++) { + char c = arr[i]; + if (c == '/') { + if (i == 0 || (i == arr.length - 1)) + continue chars; + if (curr.length() > 0) { + tokens.add(curr.toString()); + curr = new StringBuffer(); + } + } else + curr.append(c); + } + if (curr.length() > 0) { + tokens.add(curr.toString()); + curr = new StringBuffer(); + } } + return Collections.unmodifiableList(tokens); } /** @@ -359,15 +479,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(); @@ -510,16 +632,18 @@ public class JcrUtils implements ArgeoJcrConstants { relPath, p.getValue(), null); diffs.put(relPath, pDiff); } else { - if (p.isMultiple()) - continue props; - Value referenceValue = p.getValue(); - Value newValue = observed.getProperty(name).getValue(); - if (!referenceValue.equals(newValue)) { - String relPath = propertyRelPath(baseRelPath, name); - PropertyDiff pDiff = new PropertyDiff( - PropertyDiff.MODIFIED, relPath, referenceValue, - newValue); - diffs.put(relPath, pDiff); + if (p.isMultiple()) { + // FIXME implement multiple + } else { + Value referenceValue = p.getValue(); + Value newValue = observed.getProperty(name).getValue(); + if (!referenceValue.equals(newValue)) { + String relPath = propertyRelPath(baseRelPath, name); + PropertyDiff pDiff = new PropertyDiff( + PropertyDiff.MODIFIED, relPath, + referenceValue, newValue); + diffs.put(relPath, pDiff); + } } } } @@ -531,10 +655,14 @@ public class JcrUtils implements ArgeoJcrConstants { if (name.startsWith("jcr:")) continue props; if (!reference.hasProperty(name)) { - String relPath = propertyRelPath(baseRelPath, name); - PropertyDiff pDiff = new PropertyDiff(PropertyDiff.ADDED, - relPath, null, p.getValue()); - diffs.put(relPath, pDiff); + if (p.isMultiple()) { + // FIXME implement multiple + } else { + String relPath = propertyRelPath(baseRelPath, name); + PropertyDiff pDiff = new PropertyDiff( + PropertyDiff.ADDED, relPath, null, p.getValue()); + diffs.put(relPath, pDiff); + } } } } catch (RepositoryException e) { @@ -872,8 +1000,8 @@ public class JcrUtils implements ArgeoJcrConstants { Constraint constraint = qomf.comparison(userIdDop, QueryObjectModelFactory.JCR_OPERATOR_EQUAL_TO, userIdSop); Query query = qomf.createQuery(sel, constraint, null, null); - Node userHome = JcrUtils.querySingleNode(query); - return userHome; + Node userProfile = JcrUtils.querySingleNode(query); + return userProfile; } catch (RepositoryException e) { throw new ArgeoException( "Cannot find profile for user " + username, e); @@ -914,8 +1042,12 @@ public class JcrUtils implements ArgeoJcrConstants { } else { userProfile = userHome.addNode(ArgeoNames.ARGEO_PROFILE); userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE); + // session.getWorkspace().getVersionManager() + // .checkout(userProfile.getPath()); userProfile.setProperty(ArgeoNames.ARGEO_USER_ID, username); session.save(); + session.getWorkspace().getVersionManager() + .checkin(userProfile.getPath()); // we need to save the profile before adding the user home type } userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME); @@ -973,14 +1105,29 @@ public class JcrUtils implements ArgeoJcrConstants { */ public static void updateLastModified(Node node) { try { - if (node.isNodeType(NodeType.MIX_LAST_MODIFIED)) { - node.setProperty(Property.JCR_LAST_MODIFIED, - new GregorianCalendar()); - node.setProperty(Property.JCR_LAST_MODIFIED_BY, node - .getSession().getUserID()); - } + if (!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 ArgeoException("Cannot update last modified on " + node, + e); + } + } + + /** Update lastModified recursively until this parent. */ + public static void updateLastModifiedAndParents(Node node, String untilPath) { + try { + if (!node.getPath().startsWith(untilPath)) + throw new ArgeoException(node + " is not under " + untilPath); + updateLastModified(node); + if (!node.getPath().equals(untilPath)) + updateLastModifiedAndParents(node.getParent(), untilPath); } catch (RepositoryException e) { - throw new ArgeoException("Cannot update last modified", e); + throw new ArgeoException("Cannot update lastModified from " + node + + " until " + untilPath, e); } } @@ -1036,7 +1183,6 @@ public class JcrUtils implements ArgeoJcrConstants { NodeIterator ni = node.getNodes(); while (ni.hasNext()) curNodeSize += getNodeApproxSize(ni.nextNode()); - log.debug(node + ": " + curNodeSize); return curNodeSize; } catch (RepositoryException re) { throw new ArgeoException(