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=77309feea0ad8e88c507b81f279184ac3b750373;hb=019e0f2af17286be08ab17c1c9e1d8ba871ec9b2;hp=d9eeb4998d6c1a648fba54c719661bf65450a62a;hpb=3cd76e9fb547b4e839931c96264f0edc3ec315b6;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 d9eeb4998..77309feea 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,6 +23,7 @@ import java.text.ParseException; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -35,21 +36,32 @@ import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.Property; import javax.jcr.PropertyIterator; +import javax.jcr.Repository; import javax.jcr.RepositoryException; +import javax.jcr.RepositoryFactory; import javax.jcr.Session; import javax.jcr.Value; import javax.jcr.nodetype.NodeType; import javax.jcr.query.Query; import javax.jcr.query.QueryResult; +import javax.jcr.query.qom.Constraint; +import javax.jcr.query.qom.DynamicOperand; +import javax.jcr.query.qom.QueryObjectModelFactory; +import javax.jcr.query.qom.Selector; +import javax.jcr.query.qom.StaticOperand; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.ArgeoException; /** Utility methods to simplify common JCR operations. */ -public class JcrUtils { +public class JcrUtils implements ArgeoJcrConstants { private final static Log log = LogFactory.getLog(JcrUtils.class); + /** Prevents instantiation */ + private JcrUtils() { + } + /** * Queries one single node. * @@ -219,7 +231,8 @@ public class JcrUtils { } /** - * Creates the nodes making path, if they don't exist. + * Creates the nodes making path, if they don't exist. This is up to the + * caller to save the session. */ public static Node mkdirs(Session session, String path, String type, String intermediaryNodeType, Boolean versioning) { @@ -262,7 +275,7 @@ public class JcrUtils { currentNode = (Node) session.getItem(current.toString()); } } - session.save(); + // session.save(); return currentNode; } catch (RepositoryException e) { throw new ArgeoException("Cannot mkdirs " + path, e); @@ -548,9 +561,184 @@ public class JcrUtils { return name.replace(':', '_'); } + /** Cleanly disposes a {@link Binary} even if it is null. */ public static void closeQuietly(Binary binary) { if (binary == null) return; binary.dispose(); } + + /** + * Creates depth from a string (typically a username) by adding levels based + * on its first characters: "aBcD",2 => a/aB + */ + public static String firstCharsToPath(String str, Integer nbrOfChars) { + if (str.length() < nbrOfChars) + throw new ArgeoException("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++) { + curr.append(str.charAt(i)); + path.append(curr); + if (i < nbrOfChars - 1) + path.append('/'); + } + return path.toString(); + } + + /** + * Wraps the call to the repository factory based on parameter + * {@link ArgeoJcrConstants#JCR_REPOSITORY_ALIAS} in order to simplify it + * and protect against future API changes. + */ + public static Repository getRepositoryByAlias( + RepositoryFactory repositoryFactory, String alias) { + try { + Map parameters = new HashMap(); + parameters.put(JCR_REPOSITORY_ALIAS, alias); + return repositoryFactory.getRepository(parameters); + } catch (RepositoryException e) { + throw new ArgeoException( + "Unexpected exception when trying to retrieve repository with alias " + + alias, e); + } + } + + /** + * Wraps the call to the repository factory based on parameter + * {@link ArgeoJcrConstants#JCR_REPOSITORY_URI} in order to simplify it and + * protect against future API changes. + */ + public static Repository getRepositoryByUri( + RepositoryFactory repositoryFactory, String uri) { + try { + Map parameters = new HashMap(); + parameters.put(JCR_REPOSITORY_URI, uri); + return repositoryFactory.getRepository(parameters); + } catch (RepositoryException e) { + throw new ArgeoException( + "Unexpected exception when trying to retrieve repository with uri " + + uri, e); + } + } + + /** + * Discards the current changes in a session by calling + * {@link Session#refresh(boolean)} with false, only logging + * potential errors when doing so. To be used typically in a catch block. + */ + public static void discardQuietly(Session session) { + try { + if (session != null) + session.refresh(false); + } catch (RepositoryException e) { + log.warn("Cannot quietly discard session " + session + ": " + + e.getMessage()); + } + } + + /** Logs out the session, not throwing any exception, even if it is null. */ + public static void logoutQuietly(Session session) { + if (session != null) + session.logout(); + } + + /** Returns the home node of the session user or null if none was found. */ + public static Node getUserHome(Session session) { + String userID = session.getUserID(); + return getUserHome(session, userID); + } + + /** Get the profile of the user attached to this session. */ + public static Node getUserProfile(Session session) { + String userID = session.getUserID(); + return getUserProfile(session, userID); + } + + /** + * Returns the home node of the session user or null if none was found. + * + * @param session + * the session to use in order to perform the search, this can be + * a session with a different user ID than the one searched, + * typically when a system or admin session is used. + * @param userID + * the id of the user + */ + public static Node getUserHome(Session session, String userID) { + try { + QueryObjectModelFactory qomf = session.getWorkspace() + .getQueryManager().getQOMFactory(); + + // query the user home for this user id + Selector userHomeSel = qomf.selector(ArgeoTypes.ARGEO_USER_HOME, + "userHome"); + DynamicOperand userIdDop = qomf.propertyValue("userHome", + ArgeoNames.ARGEO_USER_ID); + StaticOperand userIdSop = qomf.literal(session.getValueFactory() + .createValue(userID)); + Constraint constraint = qomf.comparison(userIdDop, + QueryObjectModelFactory.JCR_OPERATOR_EQUAL_TO, userIdSop); + Query query = qomf.createQuery(userHomeSel, constraint, null, null); + Node userHome = JcrUtils.querySingleNode(query); + return userHome; + } catch (RepositoryException e) { + throw new ArgeoException("Cannot find home for user " + userID, e); + } + } + + public static Node getUserProfile(Session session, String userID) { + try { + QueryObjectModelFactory qomf = session.getWorkspace() + .getQueryManager().getQOMFactory(); + Selector sel = qomf.selector(ArgeoTypes.ARGEO_USER_PROFILE, + "userProfile"); + DynamicOperand userIdDop = qomf.propertyValue("userProfile", + ArgeoNames.ARGEO_USER_ID); + StaticOperand userIdSop = qomf.literal(session.getValueFactory() + .createValue(userID)); + 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; + } catch (RepositoryException e) { + throw new ArgeoException("Cannot find profile for user " + userID, + e); + } + } + + public static Node createUserHome(Session session, String homeBasePath, + String username) { + try { + 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 + PropertyIterator pit = userHome.getProperties(); + while (pit.hasNext()) { + Property p = pit.nextProperty(); + log.debug(p.getName() + "=" + p.getValue().getString()); + } + 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 + userHome.setProperty(ArgeoNames.ARGEO_USER_ID, username); + session.save(); + return userHome; + } catch (RepositoryException e) { + discardQuietly(session); + throw new ArgeoException("Cannot create home node for user " + + username, e); + } + } }