/*
- * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
+ * Copyright (C) 2007-2012 Mathieu Baudier
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.argeo.jcr;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
+import java.security.Principal;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
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 javax.jcr.Binary;
import javax.jcr.NamespaceRegistry;
+import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
-import javax.jcr.RepositoryFactory;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.Workspace;
import javax.jcr.observation.EventListener;
import javax.jcr.query.Query;
import javax.jcr.query.QueryResult;
-import javax.jcr.version.VersionManager;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+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;
import org.argeo.ArgeoException;
+import org.argeo.ArgeoMonitor;
+import org.argeo.util.security.DigestUtils;
+import org.argeo.util.security.SimplePrincipal;
/** Utility methods to simplify common JCR operations. */
public class JcrUtils implements ArgeoJcrConstants {
return node;
}
+ /** Retrieves the node name from the provided path */
+ public static String nodeNameFromPath(String path) {
+ if (path.equals("/"))
+ return "";
+ if (path.charAt(0) != '/')
+ throw new ArgeoException("Path " + path + " must start with a '/'");
+ String pathT = path;
+ if (pathT.charAt(pathT.length() - 1) == '/')
+ pathT = pathT.substring(0, pathT.length() - 2);
+
+ int index = pathT.lastIndexOf('/');
+ return pathT.substring(index + 1);
+ }
+
/** Retrieves the parent path of the provided path */
public static String parentPath(String path) {
if (path.equals("/"))
.addNode(childName);
}
+ /** Convert a {@link NodeIterator} to a list of {@link Node} */
+ public static List<Node> nodeIteratorToList(NodeIterator nodeIterator) {
+ List<Node> nodes = new ArrayList<Node>();
+ while (nodeIterator.hasNext()) {
+ nodes.add(nodeIterator.nextNode());
+ }
+ return nodes;
+ }
+
+ /*
+ * PROPERTIES
+ */
+
+ /**
+ * Concisely get the string value of a property or null if this node doesn't
+ * have this property
+ */
+ public static String get(Node node, String propertyName) {
+ try {
+ if (!node.hasProperty(propertyName))
+ return null;
+ return node.getProperty(propertyName).getString();
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot get property " + propertyName
+ + " of " + node, e);
+ }
+ }
+
+ /** Concisely get the boolean value of a property */
+ public static Boolean check(Node node, String propertyName) {
+ try {
+ return node.getProperty(propertyName).getBoolean();
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot get property " + propertyName
+ + " of " + node, e);
+ }
+ }
+
+ /** Concisely get the bytes array value of a property */
+ public static byte[] getBytes(Node node, String propertyName) {
+ try {
+ return getBinaryAsBytes(node.getProperty(propertyName));
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot get property " + propertyName
+ + " of " + node, e);
+ }
+ }
+
/** 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);
return mkdirsSafe(session, path, null);
}
+ /**
+ * Creates the nodes making the path as {@link NodeType#NT_FOLDER}
+ */
+ public static Node mkfolders(Session session, String path) {
+ return mkdirs(session, path, NodeType.NT_FOLDER, NodeType.NT_FOLDER,
+ false);
+ }
+
/**
* Creates the nodes making path, if they don't exist. This is up to the
* caller to save the session. Use with caution since it can create
if (session.itemExists(path)) {
Node node = session.getNode(path);
// check type
- if (type != null && !node.isNodeType(type))
+ if (type != null && !node.isNodeType(type)
+ && !node.getPath().equals("/"))
throw new ArgeoException("Node " + node
+ " exists but is of type "
+ node.getPrimaryNodeType().getName()
}
+ /** 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) {
+ StringBuffer buf = new StringBuffer("");
+ try {
+ for (AccessControlEntry ace : acl.getAccessControlEntries()) {
+ buf.append('\t').append(ace.getPrincipal().getName())
+ .append('\n');
+ for (Privilege priv : ace.getPrivileges())
+ buf.append("\t\t").append(priv.getName()).append('\n');
+ }
+ return buf.toString();
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot write summary of " + acl, e);
+ }
+ }
+
/**
* Copies recursively the content of a node to another one. Do NOT copy the
* property values of {@link NodeType#MIX_CREATED} and
*/
public static void copy(Node fromNode, Node toNode) {
try {
+ if (toNode.getDefinition().isProtected())
+ return;
+
// process properties
PropertyIterator pit = fromNode.getProperties();
properties: while (pit.hasNext()) {
}
}
+ /**
+ * Copy only nt:folder and nt:file, without their additional types and
+ * properties.
+ *
+ * @param recursive
+ * if true copies folders as well, otherwise only first level
+ * files
+ * @return how many files were copied
+ */
+ public static Long copyFiles(Node fromNode, Node toNode, Boolean recursive,
+ ArgeoMonitor monitor) {
+ long count = 0l;
+
+ Binary binary = null;
+ InputStream in = null;
+ try {
+ NodeIterator fromChildren = fromNode.getNodes();
+ while (fromChildren.hasNext()) {
+ if (monitor != null && monitor.isCanceled())
+ throw new ArgeoException(
+ "Copy cancelled before it was completed");
+
+ Node fromChild = fromChildren.nextNode();
+ String fileName = fromChild.getName();
+ if (fromChild.isNodeType(NodeType.NT_FILE)) {
+ if (monitor != null)
+ monitor.subTask("Copy " + fileName);
+ binary = fromChild.getNode(Node.JCR_CONTENT)
+ .getProperty(Property.JCR_DATA).getBinary();
+ in = binary.getStream();
+ copyStreamAsFile(toNode, fileName, in);
+ IOUtils.closeQuietly(in);
+ JcrUtils.closeQuietly(binary);
+
+ // save session
+ toNode.getSession().save();
+ count++;
+
+ if (log.isDebugEnabled())
+ log.debug("Copied file " + fromChild.getPath());
+ if (monitor != null)
+ monitor.worked(1);
+ } else if (fromChild.isNodeType(NodeType.NT_FOLDER)
+ && recursive) {
+ Node toChildFolder;
+ if (toNode.hasNode(fileName)) {
+ toChildFolder = toNode.getNode(fileName);
+ if (!toChildFolder.isNodeType(NodeType.NT_FOLDER))
+ throw new ArgeoException(toChildFolder
+ + " is not of type nt:folder");
+ } else {
+ toChildFolder = toNode.addNode(fileName,
+ NodeType.NT_FOLDER);
+
+ // save session
+ toNode.getSession().save();
+ }
+ count = count
+ + copyFiles(fromChild, toChildFolder, recursive,
+ monitor);
+ }
+ }
+ return count;
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot copy files between " + fromNode
+ + " and " + toNode);
+ } finally {
+ // in case there was an exception
+ IOUtils.closeQuietly(in);
+ JcrUtils.closeQuietly(binary);
+ }
+ }
+
/**
* Check whether all first-level properties (except jcr:* properties) are
* equal. Skip jcr:* properties
}
}
+ /**
+ * Copy a file as an nt:file, assuming an nt:folder hierarchy. The session
+ * is NOT saved.
+ *
+ * @return the created file node
+ */
+ public static Node copyFile(Node folderNode, File file) {
+ InputStream in = null;
+ try {
+ in = new FileInputStream(file);
+ return copyStreamAsFile(folderNode, file.getName(), in);
+ } catch (IOException e) {
+ throw new ArgeoException("Cannot copy file " + file + " under "
+ + folderNode, e);
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ }
+
+ /** Copy bytes as an nt:file */
+ public static Node copyBytesAsFile(Node folderNode, String fileName,
+ byte[] bytes) {
+ InputStream in = null;
+ try {
+ in = new ByteArrayInputStream(bytes);
+ return copyStreamAsFile(folderNode, fileName, in);
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot copy file " + fileName + " under "
+ + folderNode, e);
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ }
+
+ /**
+ * Copy a stream as an nt:file, assuming an nt:folder hierarchy. The session
+ * is NOT saved.
+ *
+ * @return the created file node
+ */
+ public static Node copyStreamAsFile(Node folderNode, String fileName,
+ InputStream in) {
+ Binary binary = null;
+ try {
+ Node fileNode;
+ Node contentNode;
+ if (folderNode.hasNode(fileName)) {
+ fileNode = folderNode.getNode(fileName);
+ if (!fileNode.isNodeType(NodeType.NT_FILE))
+ throw new ArgeoException(fileNode
+ + " is not of type nt:file");
+ // we assume that the content node is already there
+ contentNode = fileNode.getNode(Node.JCR_CONTENT);
+ } else {
+ fileNode = folderNode.addNode(fileName, NodeType.NT_FILE);
+ contentNode = fileNode.addNode(Node.JCR_CONTENT,
+ NodeType.NT_RESOURCE);
+ }
+ binary = contentNode.getSession().getValueFactory()
+ .createBinary(in);
+ contentNode.setProperty(Property.JCR_DATA, binary);
+ return fileNode;
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot create file node " + fileName
+ + " under " + folderNode, e);
+ } finally {
+ closeQuietly(binary);
+ }
+ }
+
+ /** Computes the checksum of an nt:file */
+ public static String checksumFile(Node fileNode, String algorithm) {
+ Binary data = null;
+ InputStream in = null;
+ try {
+ data = fileNode.getNode(Node.JCR_CONTENT)
+ .getProperty(Property.JCR_DATA).getBinary();
+ in = data.getStream();
+ return DigestUtils.digest(algorithm, in);
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot checksum file " + fileNode, e);
+ } finally {
+ IOUtils.closeQuietly(in);
+ closeQuietly(data);
+ }
+ }
+
/**
* Creates depth from a string (typically a username) by adding levels based
* on its first characters: "aBcD",2 => a/aB
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<String, String> parameters = new HashMap<String, String>();
- 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<String, String> parameters = new HashMap<String, String>();
- 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 the session attached to this node. To be
* used typically in a catch block.
}
}
+ /**
+ * Login to a workspace with implicit credentials, creates the workspace
+ * with these credentials if it does not already exist.
+ */
+ public static Session loginOrCreateWorkspace(Repository repository,
+ String workspaceName) throws RepositoryException {
+ Session workspaceSession = null;
+ Session defaultSession = null;
+ try {
+ try {
+ workspaceSession = repository.login(workspaceName);
+ } catch (NoSuchWorkspaceException e) {
+ // try to create workspace
+ defaultSession = repository.login();
+ defaultSession.getWorkspace().createWorkspace(workspaceName);
+ workspaceSession = repository.login(workspaceName);
+ }
+ return workspaceSession;
+ } finally {
+ logoutQuietly(defaultSession);
+ }
+ }
+
/** Logs out the session, not throwing any exception, even if it is null. */
public static void logoutQuietly(Session session) {
try {
try {
session.getWorkspace()
.getObservationManager()
- .addEventListener(listener, eventTypes, basePath, true,
- null, new String[] { nodeType }, true);
+ .addEventListener(
+ listener,
+ eventTypes,
+ basePath,
+ true,
+ null,
+ nodeType == null ? null : new String[] { nodeType },
+ true);
} catch (RepositoryException e) {
throw new ArgeoException("Cannot add JCR listener " + listener
+ " to session " + session, e);
}
}
- /** 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);
- }
-
- /** User home path is NOT configurable */
- public static String getUserHomePath(String username) {
- String homeBasePath = DEFAULT_HOME_BASE_PATH;
- return homeBasePath + '/' + firstCharsToPath(username, 2) + '/'
- + username;
- }
-
- /**
- * 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 username
- * the username of the user
- */
- public static Node getUserHome(Session session, String username) {
- try {
- String homePath = getUserHomePath(username);
- return session.itemExists(homePath) ? session.getNode(homePath)
- : null;
- // kept for example of QOM queries
- // QueryObjectModelFactory qomf = session.getWorkspace()
- // .getQueryManager().getQOMFactory();
- // 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(username));
- // Constraint constraint = qomf.comparison(userIdDop,
- // QueryObjectModelFactory.JCR_OPERATOR_EQUAL_TO, userIdSop);
- // Query query = qomf.createQuery(userHomeSel, constraint, null,
- // null);
- // Node userHome = JcrUtils.querySingleNode(query);
- } catch (RepositoryException e) {
- throw new ArgeoException("Cannot find home for user " + username, e);
- }
- }
-
- /**
- * Creates an Argeo user home, does nothing if it already exists. Session is
- * NOT saved.
- */
- public static Node createUserHomeIfNeeded(Session session, String username) {
- try {
- String homePath = getUserHomePath(username);
- if (session.itemExists(homePath))
- return session.getNode(homePath);
- else {
- Node userHome = JcrUtils.mkdirs(session, homePath);
- userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
- userHome.setProperty(ArgeoNames.ARGEO_USER_ID, username);
- return userHome;
- }
- } catch (RepositoryException e) {
- discardQuietly(session);
- throw new ArgeoException("Cannot create home for " + username
- + " in workspace " + session.getWorkspace().getName(), e);
- }
- }
-
- /**
- * Creates a user profile in the home of this user. Creates the home if
- * needed, but throw an exception if a profile already exists. The session
- * is not saved and the node is in a checkedOut state (that is, it requires
- * a subsequent checkin after saving the session).
- */
- public static Node createUserProfile(Session session, String username) {
- try {
- Node userHome = createUserHomeIfNeeded(session, username);
- if (userHome.hasNode(ArgeoNames.ARGEO_PROFILE))
- throw new ArgeoException(
- "There is already a user profile under " + userHome);
- Node userProfile = userHome.addNode(ArgeoNames.ARGEO_PROFILE);
- userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE);
- userProfile.setProperty(ArgeoNames.ARGEO_USER_ID, username);
- userProfile.setProperty(ArgeoNames.ARGEO_ENABLED, true);
- userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED, true);
- userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED, true);
- userProfile.setProperty(ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED,
- true);
- return userProfile;
- } catch (RepositoryException e) {
- discardQuietly(session);
- throw new ArgeoException("Cannot create user profile for "
- + username + " in workspace "
- + session.getWorkspace().getName(), e);
- }
- }
-
- /**
- * Create user profile if needed, the session IS saved.
- *
- * @return the user profile
- */
- public static Node createUserProfileIfNeeded(Session securitySession,
- String username) {
- try {
- Node userHome = JcrUtils.createUserHomeIfNeeded(securitySession,
- username);
- Node userProfile = userHome.hasNode(ArgeoNames.ARGEO_PROFILE) ? userHome
- .getNode(ArgeoNames.ARGEO_PROFILE) : JcrUtils
- .createUserProfile(securitySession, username);
- if (securitySession.hasPendingChanges())
- securitySession.save();
- VersionManager versionManager = securitySession.getWorkspace()
- .getVersionManager();
- if (versionManager.isCheckedOut(userProfile.getPath()))
- versionManager.checkin(userProfile.getPath());
- return userProfile;
- } catch (RepositoryException e) {
- discardQuietly(securitySession);
- throw new ArgeoException("Cannot create user profile for "
- + username + " in workspace "
- + securitySession.getWorkspace().getName(), e);
- }
- }
-
- /** Creates an Argeo user home. */
- // public static Node createUserHome(Session session, String homeBasePath,
- // String username) {
- // try {
- // if (session == null)
- // throw new ArgeoException("Session is null");
- // if (session.hasPendingChanges())
- // throw new ArgeoException(
- // "Session has pending changes, save them first");
- //
- // String homePath = getUserHomePath(username);
- //
- // 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);
- // // 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);
- // // 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);
- // }
- // }
-
- /**
- * Returns user home has path, embedding exceptions. Contrary to
- * {@link #getUserHome(Session)}, it never returns null but throws and
- * exception if not found.
- *
- * @deprecated use getUserHome() instead, throwing an exception if it
- * returns null
- */
- @Deprecated
- public static String getUserHomePath(Session session) {
- String userID = session.getUserID();
- try {
- String homePath = getUserHomePath(userID);
- if (session.itemExists(homePath))
- return homePath;
- else
- throw new ArgeoException("No home registered for " + userID);
- } catch (RepositoryException e) {
- throw new ArgeoException("Cannot find user home path", e);
- }
- }
-
- /**
- * @return null if not found *
- */
- public static Node getUserProfile(Session session, String username) {
- try {
- Node userHome = getUserHome(session, username);
- if (userHome == null)
- return null;
- if (userHome.hasNode(ArgeoNames.ARGEO_PROFILE))
- return userHome.getNode(ArgeoNames.ARGEO_PROFILE);
- else
- return null;
- } catch (RepositoryException e) {
- throw new ArgeoException(
- "Cannot find profile for user " + username, e);
- }
- }
-
- /**
- * Get the profile of the user attached to this session.
- */
- public static Node getUserProfile(Session session) {
- String userID = session.getUserID();
- return getUserProfile(session, userID);
- }
-
/**
* Quietly unregisters an {@link EventListener} from the udnerlying
* workspace of this node.
re);
}
}
+
+ /*
+ * SECURITY
+ */
+
+ /**
+ * Convenience method for adding a single privilege to a principal (user or
+ * role), typically jcr:all
+ */
+ public static void addPrivilege(Session session, String path,
+ String principal, String privilege) throws RepositoryException {
+ List<Privilege> privileges = new ArrayList<Privilege>();
+ privileges.add(session.getAccessControlManager().privilegeFromName(
+ privilege));
+ addPrivileges(session, path, new SimplePrincipal(principal), privileges);
+ }
+
+ /**
+ * Add privileges on a path to a {@link Principal}. The path must already
+ * exist. Session is saved.
+ */
+ public static void addPrivileges(Session session, String path,
+ Principal principal, List<Privilege> privs)
+ throws RepositoryException {
+ AccessControlManager acm = session.getAccessControlManager();
+ AccessControlList acl = getAccessControlList(acm, path);
+ acl.addAccessControlEntry(principal,
+ privs.toArray(new Privilege[privs.size()]));
+ 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
+ + " on " + path);
+ }
+ session.save();
+ }
+
+ /** Gets access control list for this path, throws exception if not found */
+ public static AccessControlList getAccessControlList(
+ AccessControlManager acm, String path) throws RepositoryException {
+ // search for an access control list
+ AccessControlList acl = null;
+ AccessControlPolicyIterator policyIterator = acm
+ .getApplicablePolicies(path);
+ if (policyIterator.hasNext()) {
+ while (policyIterator.hasNext()) {
+ AccessControlPolicy acp = policyIterator
+ .nextAccessControlPolicy();
+ if (acp instanceof AccessControlList)
+ acl = ((AccessControlList) acp);
+ }
+ } else {
+ AccessControlPolicy[] existingPolicies = acm.getPolicies(path);
+ for (AccessControlPolicy acp : existingPolicies) {
+ if (acp instanceof AccessControlList)
+ acl = ((AccessControlList) acp);
+ }
+ }
+ if (acl != null)
+ return acl;
+ else
+ throw new ArgeoException("ACL not found at " + path);
+ }
+
+ /** Clear authorizations for a user at this path */
+ public static void clearAccessControList(Session session, String path,
+ String username) throws RepositoryException {
+ AccessControlManager acm = session.getAccessControlManager();
+ AccessControlList acl = getAccessControlList(acm, path);
+ for (AccessControlEntry ace : acl.getAccessControlEntries()) {
+ if (ace.getPrincipal().getName().equals(username)) {
+ acl.removeAccessControlEntry(ace);
+ }
+ }
+ }
}