You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2009/10/22 19:26:39 UTC
svn commit: r828791 [4/8] - in /jackrabbit/trunk:
jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/
jackrabbit-core/src/main/java/org/apache/jackrabbit/core/
jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ jackrabbi...
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java Thu Oct 22 17:26:37 2009
@@ -41,8 +41,8 @@
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
-import javax.jcr.Session;
import javax.jcr.ItemNotFoundException;
+import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.version.VersionException;
@@ -78,8 +78,8 @@
* <ul>
* <li>The names of the hierarchy folders is determined from ID of the
* authorizable to be created, consisting of the leading N chars where N is
- * the relative depth starting from the node at {@link UserConstants#USERS_PATH}
- * or {@link UserConstants#GROUPS_PATH}.</li>
+ * the relative depth starting from the node at {@link #getUsersPath()}
+ * or {@link #getGroupsPath()}.</li>
* <li>By default 2 levels (depth == 2) are created.</li>
* <li>Parent nodes are expected to consist of folder structure only.</li>
* <li>If the ID contains invalid JCR chars that would prevent the creation of
@@ -222,8 +222,8 @@
private final String groupsPath;
/**
- * Flag indicating if {@link #getAuthorizable(String)} should find users or
- * groups created with Jackrabbit < 2.0.<br>
+ * Flag indicating if {@link #getAuthorizable(String)} should be able to deal
+ * with users or groups created with Jackrabbit < 2.0.<br>
* As of 2.0 authorizables are created using a defined logic that allows
* to retrieve them without searching/traversing. If this flag is
* <code>true</code> this method will try to find authorizables using the
@@ -232,22 +232,11 @@
private final boolean compatibleJR16;
/**
- * Flat storing the batch modus.
- * If this option is turned on changes made through this user manager will
- * only be persisted upon an explicit call to {@link javax.jcr.Session#save()},
- * which must be the editing session object. Otherwise (default behavior)
- * changes are immediately persisted.
- *
- * @see #setPersistenceModus(boolean, Session)
- */
- boolean batchModus = false;
-
- /**
* Create a new <code>UserManager</code> with the default configuration.
*
- * @param session
- * @param adminId
- * @throws RepositoryException
+ * @param session The editing/reading session.
+ * @param adminId The user ID of the administrator.
+ * @throws RepositoryException If an error occurs.
*/
public UserManagerImpl(SessionImpl session, String adminId) throws RepositoryException {
this(session, adminId, null);
@@ -267,10 +256,10 @@
*
* See the overall {@link UserManagerImpl introduction} for details.
*
- * @param session
- * @param adminId
- * @param config
- * @throws RepositoryException
+ * @param session The editing/reading session.
+ * @param adminId The user ID of the administrator.
+ * @param config The configuration parameters.
+ * @throws RepositoryException If an error occurs.
*/
public UserManagerImpl(SessionImpl session, String adminId, Properties config) throws RepositoryException {
this.session = session;
@@ -297,23 +286,7 @@
authResolver = nr;
authResolver.setSearchRoots(usersPath, groupsPath);
}
-
- /**
- * @param batched If <code>true</code> changes made through this manager and
- * to authorizables are only persisted upon explict call to {@link
- * javax.jcr.Session#save()}.
- * @throws RepositoryException If the passed <code>editingSession</code> is
- * not the same this UserManager is writing to.
- */
- /* COMMENTED. WORK IN PROGRESS
- public void setPersistenceModus(boolean batched, Session editingSession) throws RepositoryException {
- if (editingSession != session) {
- throw new RepositoryException("Cannot change persistence modus: Session mismatch.");
- }
- batchModus = batched;
- }
- */
-
+
/**
* Implementation specific methods releaving where users are created within
* the content.
@@ -344,36 +317,7 @@
if (id == null || id.length() == 0) {
throw new IllegalArgumentException("Invalid authorizable name '" + id + "'");
}
- Authorizable authorz = null;
- NodeId nodeId = buildNodeId(id);
- NodeImpl n = null;
- try {
- n = session.getNodeById(nodeId);
- } catch (ItemNotFoundException e) {
- if (compatibleJR16) {
- // backwards-compatibility with JR < 2.0 user/group structure that doesn't
- // allow to determine existance of an authorizable from the id directly.
- // search for it the node belonging to that id
- n = (NodeImpl) authResolver.findNode(P_USERID, id, NT_REP_USER);
- if (n == null) {
- // no user -> look for group.
- // NOTE: JR < 2.0 always returned groupIDs that didn't contain any
- // illegal JCR chars. Since Group.getID() now unescapes the node
- // name additional escaping is required.
- Name nodeName = session.getQName(Text.escapeIllegalJcrChars(id));
- n = (NodeImpl) authResolver.findNode(nodeName, NT_REP_GROUP);
- }
- } // else: no matching node found -> ignore exception.
- }
-
- if (n != null) {
- if (n.isNodeType(NT_REP_USER)) {
- authorz = createUser(n);
- } else if (n.isNodeType(NT_REP_GROUP)) {
- authorz = createGroup(n);
- } // else some other node but not an authorizable -> return null.
- } // else no matching node -> return null.
- return authorz;
+ return internalGetAuthorizable(id);
}
/**
@@ -391,34 +335,37 @@
}
}
} else {
- // another Principal -> search
- String name = principal.getName();
+ // another Principal implementation.
+ // a) try short-cut that works in case of ID.equals(principalName) only.
+ // b) execute query in case of pName mismatch or exc. however, query
+ // requires persisted user nodes (see known issue of UserImporter).
+ String name = principal.getName();
+ try {
+ Authorizable a = internalGetAuthorizable(name);
+ if (a != null && name.equals(a.getPrincipal().getName())) {
+ return a;
+ }
+ } catch (RepositoryException e) {
+ // ignore and execute the query.
+ }
+ // shortcut didn't work -> search.
n = (NodeImpl) authResolver.findNode(P_PRINCIPAL_NAME, name, NT_REP_AUTHORIZABLE);
}
// build the corresponding authorizable object
- if (n != null) {
- if (n.isNodeType(NT_REP_USER)) {
- return createUser(n);
- } else if (n.isNodeType(NT_REP_GROUP)) {
- return createGroup(n);
- } else {
- log.debug("Unexpected user nodetype " + n.getPrimaryNodeType().getName());
- }
- }
- return null;
+ return getAuthorizable(n);
}
/**
* @see UserManager#findAuthorizables(String,String)
*/
- public Iterator findAuthorizables(String propertyName, String value) throws RepositoryException {
+ public Iterator<Authorizable> findAuthorizables(String propertyName, String value) throws RepositoryException {
return findAuthorizables(propertyName, value, SEARCH_TYPE_AUTHORIZABLE);
}
/**
* @see UserManager#findAuthorizables(String,String, int)
*/
- public Iterator findAuthorizables(String propertyName, String value, int searchType)
+ public Iterator<Authorizable> findAuthorizables(String propertyName, String value, int searchType)
throws RepositoryException {
Name name = session.getQName(propertyName);
Name ntName;
@@ -474,27 +421,22 @@
if (password == null) {
throw new IllegalArgumentException("Cannot create user: null password.");
}
- if (!isValidPrincipal(principal)) {
- throw new IllegalArgumentException("Cannot create user: Principal may not be null and must have a valid name.");
- }
- if (getAuthorizable(userID) != null) {
+ if (internalGetAuthorizable(userID) != null) {
throw new AuthorizableExistsException("User for '" + userID + "' already exists");
}
- if (hasAuthorizable(principal)) {
- throw new AuthorizableExistsException("Authorizable for '" + principal.getName() + "' already exists");
- }
try {
NodeImpl userNode = (NodeImpl) nodeCreator.createUserNode(userID, intermediatePath);
-
+ setPrincipal(userNode, principal);
setProperty(userNode, P_PASSWORD, getValue(UserImpl.buildPasswordValue(password)), true);
- setProperty(userNode, P_PRINCIPAL_NAME, getValue(principal.getName()), true);
- if (!batchModus) {
+
+ User user = createUser(userNode);
+ if (isAutoSave()) {
session.save();
}
log.debug("User created: " + userID + "; " + userNode.getPath());
- return createUser(userNode);
+ return user;
} catch (RepositoryException e) {
// something went wrong -> revert changes and rethrow
session.refresh(false);
@@ -514,7 +456,7 @@
/**
* Create a new <code>Group</code> from the given <code>principal</code>.
- * It will be created below the this {@link #GROUPS_PATH group path}.<br>
+ * It will be created below the defined {@link #getGroupsPath() group path}.<br>
* Non-existant elements of the Path will be created as nodes
* of type {@link #NT_REP_AUTHORIZABLE_FOLDER rep:AuthorizableFolder}.
* The group ID will be generated from the principal name. If the name
@@ -531,24 +473,20 @@
*/
public Group createGroup(Principal principal, String intermediatePath) throws AuthorizableExistsException, RepositoryException {
if (!isValidPrincipal(principal)) {
- throw new IllegalArgumentException("Cannot create Group: Principal may not be null and must have a valid name.");
+ throw new IllegalArgumentException("Cannot create group: Principal may not be null and must have a valid name.");
}
- if (hasAuthorizable(principal)) {
- throw new AuthorizableExistsException("Authorizable for '" + principal.getName() + "' already exists: ");
- }
-
try {
String groupID = getGroupId(principal.getName());
NodeImpl groupNode = (NodeImpl) nodeCreator.createGroupNode(groupID, intermediatePath);
+ setPrincipal(groupNode, principal);
- setProperty(groupNode, P_PRINCIPAL_NAME, getValue(principal.getName()));
- if (!batchModus) {
+ Group group = createGroup(groupNode);
+ if (isAutoSave()) {
session.save();
}
log.debug("Group created: " + groupID + "; " + groupNode.getPath());
-
- return createGroup(groupNode);
+ return group;
} catch (RepositoryException e) {
session.refresh(false);
log.debug("newInstance new Group failed, revert changes on parent");
@@ -556,46 +494,100 @@
}
}
- //--------------------------------------------------------------------------
/**
+ * Always returns <code>true</code> as by default the autoSave behavior
+ * cannot be altered (see also {@link #autoSave(boolean)}.
*
- * @param principal
- * @return
- * @throws RepositoryException
+ * @return Always <code>true</code>.
+ * @see org.apache.jackrabbit.api.security.user.UserManager#isAutoSave()
+ */
+ public boolean isAutoSave() {
+ return true;
+ }
+
+ /**
+ * Always throws <code>unsupportedRepositoryOperationException</code> as
+ * modification of the autosave behavior is not supported.
+ *
+ * @see UserManager#autoSave(boolean)
*/
- private boolean hasAuthorizable(Principal principal) throws RepositoryException {
- return getAuthorizable(principal) != null;
+ public void autoSave(boolean enable) throws UnsupportedRepositoryOperationException, RepositoryException {
+ throw new UnsupportedRepositoryOperationException("Cannot change autosave behavior.");
+ }
+
+ //--------------------------------------------------------------------------
+ void setPrincipal(NodeImpl node, Principal principal) throws AuthorizableExistsException, RepositoryException {
+ if (!isValidPrincipal(principal)) {
+ throw new IllegalArgumentException("Cannot create Authorizable: Principal may not be null and must have a valid name.");
+ }
+ if (getAuthorizable(principal) != null) {
+ throw new AuthorizableExistsException("Authorizable for '" + principal.getName() + "' already exists: ");
+ }
+ if (!node.isNew() || node.hasProperty(P_PRINCIPAL_NAME)) {
+ throw new RepositoryException("rep:principalName can only be set once on a new node.");
+ }
+ setProperty(node, P_PRINCIPAL_NAME, getValue(principal.getName()), true);
}
void setProtectedProperty(NodeImpl node, Name propName, Value value) throws RepositoryException, LockException, ConstraintViolationException, ItemExistsException, VersionException {
setProperty(node, propName, value);
- if (!batchModus) {
+ if (isAutoSave()) {
node.save();
}
}
void setProtectedProperty(NodeImpl node, Name propName, Value[] values) throws RepositoryException, LockException, ConstraintViolationException, ItemExistsException, VersionException {
setProperty(node, propName, values);
- if (!batchModus) {
+ if (isAutoSave()) {
node.save();
}
}
void setProtectedProperty(NodeImpl node, Name propName, Value[] values, int type) throws RepositoryException, LockException, ConstraintViolationException, ItemExistsException, VersionException {
setProperty(node, propName, values, type);
- if (!batchModus) {
+ if (isAutoSave()) {
node.save();
}
}
void removeProtectedItem(ItemImpl item, Node parent) throws RepositoryException, AccessDeniedException, VersionException {
removeItem(item);
- if (!batchModus) {
+ if (isAutoSave()) {
parent.save();
}
}
/**
+ * Implementation specific method used to retrieve a user/group by Node.
+ * <code>Null</code> is returned if
+ * <pre>
+ * - the passed node is <code>null</code>,
+ * - doesn't have the correct node type or
+ * - isn't placed underneith the configured user/group tree.
+ * </pre>
+ *
+ * @param n
+ * @return An authorizable or <code>null</code>.
+ * @throws RepositoryException
+ */
+ Authorizable getAuthorizable(NodeImpl n) throws RepositoryException {
+ Authorizable authorz = null;
+ if (n != null) {
+ String path = n.getPath();
+ if (n.isNodeType(NT_REP_USER) && Text.isDescendant(usersPath, path)) {
+ authorz = createUser(n);
+ } else if (n.isNodeType(NT_REP_GROUP) && Text.isDescendant(groupsPath, path)) {
+ authorz = createGroup(n);
+ } else {
+ /* else some other node type or outside of the valid user/group
+ hierarchy -> return null. */
+ log.debug("Unexpected user nodetype " + n.getPrimaryNodeType().getName());
+ }
+ } /* else no matching node -> return null */
+ return authorz;
+ }
+
+ /**
* Test if a user or group exists that has the given principals name as ID,
* which might happen if userID != principal-name.
* In this case: generate another ID for the group to be created.
@@ -607,13 +599,43 @@
private String getGroupId(String principalName) throws RepositoryException {
String groupID = principalName;
int i = 0;
- while (getAuthorizable(groupID) != null) {
+ while (internalGetAuthorizable(groupID) != null) {
groupID = principalName + "_" + i;
i++;
}
return groupID;
}
+ /**
+ * @param id The user or group ID.
+ * @return The authorizable with the given <code>id</code> or <code>null</code>.
+ * @throws RepositoryException If an error occurs.
+ */
+ private Authorizable internalGetAuthorizable(String id) throws RepositoryException {
+ NodeId nodeId = buildNodeId(id);
+ NodeImpl n = null;
+ try {
+ n = session.getNodeById(nodeId);
+ } catch (ItemNotFoundException e) {
+ if (compatibleJR16) {
+ // backwards-compatibility with JR < 2.0 user/group structure that doesn't
+ // allow to determine existance of an authorizable from the id directly.
+ // search for it the node belonging to that id
+ n = (NodeImpl) authResolver.findNode(P_USERID, id, NT_REP_USER);
+ if (n == null) {
+ // no user -> look for group.
+ // NOTE: JR < 2.0 always returned groupIDs that didn't contain any
+ // illegal JCR chars. Since Group.getID() now unescapes the node
+ // name additional escaping is required.
+ Name nodeName = session.getQName(Text.escapeIllegalJcrChars(id));
+ n = (NodeImpl) authResolver.findNode(nodeName, NT_REP_GROUP);
+ }
+ } // else: no matching node found -> ignore exception.
+ }
+
+ return getAuthorizable(n);
+ }
+
private Value getValue(String strValue) throws RepositoryException {
return session.getValueFactory().createValue(strValue);
}
@@ -638,7 +660,7 @@
throw new IllegalArgumentException();
}
if (!Text.isDescendant(usersPath, userNode.getPath())) {
- throw new IllegalArgumentException("User has to be within the User Path");
+ throw new RepositoryException("User has to be within the User Path");
}
return doCreateUser(userNode);
}
@@ -648,7 +670,7 @@
* return a custom implementation.
*
* @param node user node
- * @return user object
+ * @return the user object
* @throws RepositoryException if an error occurs
*/
protected User doCreateUser(NodeImpl node) throws RepositoryException {
@@ -664,27 +686,47 @@
* @throws RepositoryException
*/
Group createGroup(NodeImpl groupNode) throws RepositoryException {
- return GroupImpl.create(groupNode, this);
+ if (groupNode == null || !groupNode.isNodeType(NT_REP_GROUP)) {
+ throw new IllegalArgumentException();
+ }
+ if (!Text.isDescendant(groupsPath, groupNode.getPath())) {
+ throw new RepositoryException("Group has to be within the Group Path");
+ }
+ return doCreateGroup(groupNode);
}
- private static boolean isValidPrincipal(Principal principal) {
- return principal != null && principal.getName() != null && principal.getName().length() > 0;
+ /**
+ * Build the group object from the given group node. May be overridden to
+ * return a custom implementation.
+ *
+ * @param node group node
+ * @return A group
+ * @throws RepositoryException if an error occurs
+ */
+ protected Group doCreateGroup(NodeImpl node) throws RepositoryException {
+ return new GroupImpl(node, this);
}
/**
+ * Creates a UUID from the given <code>id</code> String that is converted
+ * to lower case before.
*
- * @param id
- * @return
- * @throws RepositoryException
+ * @param id The user/group id that needs to be converted to a valid NodeId.
+ * @return a new <code>NodeId</code>.
+ * @throws RepositoryException If an error occurs.
*/
- private static NodeId buildNodeId(String id) throws RepositoryException {
+ private NodeId buildNodeId(String id) throws RepositoryException {
try {
- UUID uuid = UUID.nameUUIDFromBytes(id.getBytes("UTF-8"));
+ UUID uuid = UUID.nameUUIDFromBytes(id.toLowerCase().getBytes("UTF-8"));
return new NodeId(uuid);
} catch (UnsupportedEncodingException e) {
throw new RepositoryException("Unexpected error while build ID hash", e);
}
}
+
+ private static boolean isValidPrincipal(Principal principal) {
+ return principal != null && principal.getName() != null && principal.getName().length() > 0;
+ }
//----------------------------------------------------< SessionListener >---
/**
@@ -704,11 +746,11 @@
}
}
- //--------------------------------------------------------------------------
+ //------------------------------------------------------< inner classes >---
/**
* Inner class
*/
- private final class AuthorizableIterator implements Iterator {
+ private final class AuthorizableIterator implements Iterator<Authorizable> {
private final Set<String> served = new HashSet<String>();
@@ -731,7 +773,7 @@
/**
* @see Iterator#next()
*/
- public Object next() {
+ public Authorizable next() {
Authorizable authr = next;
if (authr == null) {
throw new NoSuchElementException();
@@ -753,17 +795,11 @@
NodeImpl node = (NodeImpl) authNodeIter.nextNode();
try {
if (!served.contains(node.getUUID())) {
- Authorizable authr;
- if (node.isNodeType(NT_REP_USER)) {
- authr = createUser(node);
- } else if (node.isNodeType(NT_REP_GROUP)) {
- authr = createGroup(node);
- } else {
- log.warn("Ignoring unexpected nodetype: " + node.getPrimaryNodeType().getName());
- continue;
- }
+ Authorizable authr = getAuthorizable(node);
served.add(node.getUUID());
- return authr;
+ if (authr != null) {
+ return authr;
+ }
}
} catch (RepositoryException e) {
log.debug(e.getMessage());
@@ -988,34 +1024,51 @@
Name ntName = (isGroup) ? NT_REP_GROUP : NT_REP_USER;
NodeId nid = buildNodeId(id);
+ // check if there exists an colliding folder child node.
+ while (((NodeImpl) folder).hasNode(nodeName)) {
+ NodeImpl colliding = ((NodeImpl) folder).getNode(nodeName);
+ if (colliding.isNodeType(NT_REP_AUTHORIZABLE_FOLDER)) {
+ log.warn("Existing folder node collides with user/group to be created. Expanding path: " + colliding.getPath());
+ folder = colliding;
+ } else {
+ // should never get here as folder creation above already
+ // asserts that only rep:authorizable folders exist.
+ // similarly collisions with existing authorizable have been
+ // checked.
+ String msg = "Failed to create authorizable node: Detected conflicting node of unexpected nodetype '" + colliding.getPrimaryNodeType().getName() + "'.";
+ log.error(msg);
+ throw new ConstraintViolationException(msg);
+ }
+ }
return addNode((NodeImpl) folder, nodeName, ntName, nid);
}
private Node createDefaultFolderNodes(String id, String escapedId,
boolean isGroup, String intermediatePath) throws RepositoryException {
- NodeImpl folder;
+
String defaultPath = getDefaultFolderPath(id, isGroup, intermediatePath);
- if (session.nodeExists(defaultPath)) {
- folder = (NodeImpl) session.getNode(defaultPath);
- if (!folder.isNodeType(NT_REP_AUTHORIZABLE_FOLDER)) {
- throw new RepositoryException("Invalid intermediate path. Must be of type rep:AuthorizableFolder.");
- }
- } else {
- String[] segmts = defaultPath.split("/");
- folder = (NodeImpl) session.getRootNode();
- for (String segment : segmts) {
- if (segment.length() < 1) {
- continue;
- }
- if (folder.hasNode(segment)) {
- folder = (NodeImpl) folder.getNode(segment);
- if (!folder.isNodeType(NT_REP_AUTHORIZABLE_FOLDER)) {
- throw new RepositoryException("Invalid intermediate path. Must be of type rep:AuthorizableFolder.");
- }
- } else {
- folder = addNode(folder, session.getQName(segment), NT_REP_AUTHORIZABLE_FOLDER);
+ // make sure users/groups are never nested and exclusively created
+ // under a tree of rep:AuthorizableFolder(s) starting at usersPath
+ // or groupsPath, respectively. ancestors of the usersPath/groupsPath
+ // may or may not be rep:AuthorizableFolder(s).
+ // therefore the shortcut Session.getNode(defaultPath) is omitted.
+ String[] segmts = defaultPath.split("/");
+ NodeImpl folder = (NodeImpl) session.getRootNode();
+ String authRoot = (isGroup) ? groupsPath : usersPath;
+
+ for (String segment : segmts) {
+ if (segment.length() < 1) {
+ continue;
+ }
+ if (folder.hasNode(segment)) {
+ folder = (NodeImpl) folder.getNode(segment);
+ if (Text.isDescendantOrEqual(authRoot, folder.getPath()) &&
+ !folder.isNodeType(NT_REP_AUTHORIZABLE_FOLDER)) {
+ throw new ConstraintViolationException("Invalid intermediate path. Must be of type rep:AuthorizableFolder.");
}
+ } else {
+ folder = addNode(folder, session.getQName(segment), NT_REP_AUTHORIZABLE_FOLDER);
}
}
@@ -1099,7 +1152,7 @@
// should never get here: some other, unexpected node type
String msg = "Failed to create authorizable node: Detected conflict with node of unexpected nodetype '" + n.getPrimaryNodeType().getName() + "'.";
log.error(msg);
- throw new RepositoryException(msg);
+ throw new ConstraintViolationException(msg);
}
} else {
// folder doesn't exist nor does another colliding child node.
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserPerWorkspaceUserManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserPerWorkspaceUserManager.java?rev=828791&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserPerWorkspaceUserManager.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserPerWorkspaceUserManager.java Thu Oct 22 17:26:37 2009
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.user;
+
+import org.apache.jackrabbit.core.SessionImpl;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import java.util.Properties;
+
+/**
+ * Derived UserManager implementation that allows to switch between autosaving
+ * and transient change mode.
+ * <p/>
+ * NOTE: This requires that the Session passed to the user manager upon creation
+ * is identical to the Session passed to
+ * {@link org.apache.jackrabbit.core.security.JackrabbitSecurityManager#getUserManager(Session)}.
+ *
+ * @see UserPerWorkspaceUserManager
+ */
+public class UserPerWorkspaceUserManager extends UserManagerImpl {
+
+ private boolean autoSave = true;
+
+ /**
+ * Same as <code>TransientChangeUserManagerImpl(session, adminID, null)</code>.
+ *
+ * @param session
+ * @param adminId
+ * @throws RepositoryException
+ */
+ public UserPerWorkspaceUserManager(SessionImpl session, String adminId) throws RepositoryException {
+ this(session, adminId, null);
+ }
+
+ /**
+ * Creates a UserManager that doesn't implicitly save changes but requires
+ * an explicit call to {@link javax.jcr.Session#save()}.
+ *
+ * @param session
+ * @param adminId
+ * @param config
+ * @throws javax.jcr.RepositoryException
+ */
+ public UserPerWorkspaceUserManager(SessionImpl session, String adminId, Properties config) throws RepositoryException {
+ super(session, adminId, config);
+ }
+
+ //--------------------------------------------------------< UserManager >---
+ /**
+ * @see org.apache.jackrabbit.api.security.user.UserManager#isAutoSave()
+ */
+ @Override
+ public boolean isAutoSave() {
+ return autoSave;
+ }
+
+ /**
+ * @see org.apache.jackrabbit.api.security.user.UserManager#autoSave(boolean)
+ */
+ @Override
+ public void autoSave(boolean enable) throws UnsupportedRepositoryOperationException, RepositoryException {
+ autoSave = enable;
+ }
+}
\ No newline at end of file
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/ReferenceChangeTracker.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/ReferenceChangeTracker.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/ReferenceChangeTracker.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/ReferenceChangeTracker.java Thu Oct 22 17:26:37 2009
@@ -22,6 +22,7 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import java.util.List;
/**
* Simple helper class that can be used to keep track of node id mappings
@@ -91,4 +92,15 @@
public Iterator<Object> getProcessedReferences() {
return references.iterator();
}
+
+ /**
+ * Remove the given references that have already been processed from the
+ * references list.
+ *
+ * @param processedReferences
+ * @return <code>true</code> if the internal list of references changed.
+ */
+ public boolean removeReferences(List<Object> processedReferences) {
+ return references.removeAll(processedReferences);
+ }
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/AccessControlImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/AccessControlImporter.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/AccessControlImporter.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/AccessControlImporter.java Thu Oct 22 17:26:37 2009
@@ -41,6 +41,7 @@
import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.util.ReferenceChangeTracker;
import org.apache.jackrabbit.core.id.NodeId;
import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
import org.apache.jackrabbit.core.security.principal.UnknownPrincipal;
@@ -75,27 +76,44 @@
ACE_NODETYPES.add(AccessControlConstants.NT_REP_GRANT_ACE);
}
- private final AccessControlManager acMgr;
private final Stack<Integer> prevStatus = new Stack<Integer>();
-
+
+ private AccessControlManager acMgr;
private int status = STATUS_UNDEFINED;
private NodeImpl parent = null;
private boolean principalbased = false;
+ private boolean initialized = false;
+
/**
* the ACL for non-principal based
*/
private JackrabbitAccessControlList acl = null;
- public AccessControlImporter(JackrabbitSession session, NamePathResolver resolver,
- boolean isWorkspaceImport, int uuidBehavior) throws RepositoryException {
- super(session, resolver, isWorkspaceImport, uuidBehavior);
-
- acMgr = session.getAccessControlManager();
+ @Override
+ public boolean init(JackrabbitSession session, NamePathResolver resolver,
+ boolean isWorkspaceImport, int uuidBehavior,
+ ReferenceChangeTracker referenceTracker) {
+ if (super.init(session, resolver, isWorkspaceImport, uuidBehavior, referenceTracker)) {
+ if (initialized) {
+ throw new IllegalStateException("Already initialized");
+ }
+ try {
+ acMgr = session.getAccessControlManager();
+ initialized = true;
+ } catch (RepositoryException e) {
+ // initialization failed. ac-import not possible
+ }
+ }
+ return initialized;
}
+ @Override
public boolean start(NodeImpl protectedParent) throws RepositoryException {
+ if (!initialized) {
+ throw new IllegalStateException("Not initialized");
+ }
if (isStarted()) {
// only ok if same parent
if (!protectedParent.isSame(parent)) {
@@ -116,7 +134,7 @@
&& protectedParent.isNodeType(AccessControlConstants.NT_REP_ACL)) {
acl = getACL(protectedParent.getParent().getPath());
if (acl == null) {
- log.warn("AccessControlImporter cannot be started: no ACL for {}.", parent.getParent().getPath());
+ log.warn("AccessControlImporter cannot be started: no ACL for {}.", protectedParent.getParent().getPath());
return false;
}
status = STATUS_ACL;
@@ -155,6 +173,7 @@
return acl;
}
+ @Override
public boolean start(NodeState protectedParent) throws IllegalStateException, RepositoryException {
if (isStarted()) {
throw new IllegalStateException();
@@ -166,16 +185,17 @@
return false;
}
+ @Override
public void end(NodeImpl protectedParent) throws RepositoryException {
if (!isStarted()) {
return;
}
if (!principalbased) {
- checkStatus(STATUS_ACL, "");
+ checkStatus(STATUS_ACL, "STATUS_ACL expected.");
acMgr.setPolicy(acl.getPath(), acl);
} else {
- checkStatus(STATUS_AC_FOLDER, "");
+ checkStatus(STATUS_AC_FOLDER, "STATUS_AC_FOLDER expected.");
if (!prevStatus.isEmpty()) {
throw new ConstraintViolationException("Incomplete protected item tree: "+ prevStatus.size()+ " calls to 'endChildInfo' missing.");
}
@@ -183,10 +203,12 @@
reset();
}
+ @Override
public void end(NodeState protectedParent) throws IllegalStateException, ConstraintViolationException, RepositoryException {
// nothing to do. will never get here.
}
+ @Override
public void startChildInfo(NodeInfo childInfo, List<PropInfo> propInfos) throws RepositoryException {
if (!isStarted()) {
return;
@@ -240,9 +262,7 @@
prevStatus.push(previousStatus);
}
- /**
- * @throws javax.jcr.RepositoryException
- */
+ @Override
public void endChildInfo() throws RepositoryException {
if (!isStarted()) {
return;
@@ -261,7 +281,6 @@
status = prevStatus.pop();
}
-
private boolean isStarted() {
return status > STATUS_UNDEFINED;
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedNodeImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedNodeImporter.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedNodeImporter.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedNodeImporter.java Thu Oct 22 17:26:37 2009
@@ -21,6 +21,7 @@
import javax.jcr.RepositoryException;
import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.util.ReferenceChangeTracker;
import org.apache.jackrabbit.core.state.NodeState;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
@@ -30,25 +31,24 @@
*/
public class DefaultProtectedNodeImporter implements ProtectedNodeImporter {
- protected final JackrabbitSession session;
+ protected JackrabbitSession session;
+ protected NamePathResolver resolver;
+ protected boolean isWorkspaceImport;
+ protected int uuidBehavior;
+ protected ReferenceChangeTracker referenceTracker;
- protected final NamePathResolver resolver;
-
- protected final boolean isWorkspaceImport;
-
- protected final int uuidBehavior;
+ public DefaultProtectedNodeImporter() {
+ }
- public DefaultProtectedNodeImporter(JackrabbitSession session,
- NamePathResolver resolver,
- boolean isWorkspaceImport,
- int uuidBehavior) {
+ public boolean init(JackrabbitSession session, NamePathResolver resolver, boolean isWorkspaceImport, int uuidBehavior, ReferenceChangeTracker referenceTracker) {
this.session = session;
this.resolver = resolver;
this.isWorkspaceImport = isWorkspaceImport;
this.uuidBehavior = uuidBehavior;
+ this.referenceTracker = referenceTracker;
+ return true;
}
-
/**
* Always returns <code>false</code>.
*
@@ -98,4 +98,12 @@
*/
public void endChildInfo() throws RepositoryException {
}
+
+ /**
+ * Does nothing.
+ *
+ * @see ProtectedNodeImporter#processReferences()
+ */
+ public void processReferences() throws RepositoryException {
+ }
}
\ No newline at end of file
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedPropertyImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedPropertyImporter.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedPropertyImporter.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DefaultProtectedPropertyImporter.java Thu Oct 22 17:26:37 2009
@@ -19,6 +19,7 @@
import javax.jcr.RepositoryException;
import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.util.ReferenceChangeTracker;
import org.apache.jackrabbit.core.state.NodeState;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
@@ -29,18 +30,28 @@
*/
public class DefaultProtectedPropertyImporter implements ProtectedPropertyImporter {
- protected final JackrabbitSession session;
+ protected JackrabbitSession session;
- protected final NamePathResolver resolver;
+ protected NamePathResolver resolver;
- protected final boolean isWorkspaceImport;
+ protected boolean isWorkspaceImport;
- public DefaultProtectedPropertyImporter(JackrabbitSession session,
- NamePathResolver resolver,
- boolean isWorkspaceImport) {
+ protected int uuidBehavior;
+
+ protected ReferenceChangeTracker referenceTracker;
+
+ public DefaultProtectedPropertyImporter() {
+ }
+
+ public boolean init(JackrabbitSession session, NamePathResolver resolver,
+ boolean isWorkspaceImport,
+ int uuidBehavior, ReferenceChangeTracker referenceTracker) {
this.session = session;
this.resolver = resolver;
this.isWorkspaceImport = isWorkspaceImport;
+ this.uuidBehavior = uuidBehavior;
+ this.referenceTracker = referenceTracker;
+ return true;
}
/**
@@ -48,7 +59,7 @@
*
* @see ProtectedPropertyImporter#handlePropInfo(org.apache.jackrabbit.core.NodeImpl, PropInfo, QPropertyDefinition)
*/
- public boolean handlePropInfo(NodeImpl parent, PropInfo protectedPropInfo, QPropertyDefinition def) {
+ public boolean handlePropInfo(NodeImpl parent, PropInfo protectedPropInfo, QPropertyDefinition def) throws RepositoryException {
return false;
}
@@ -60,4 +71,12 @@
public boolean handlePropInfo(NodeState parent, PropInfo protectedPropInfo, QPropertyDefinition def) throws RepositoryException {
return false;
}
+
+ /**
+ * Always returns <code>false</code>.
+ *
+ * @see ProtectedPropertyImporter#processReferences()
+ */
+ public void processReferences() throws RepositoryException {
+ }
}
\ No newline at end of file
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedNodeImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedNodeImporter.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedNodeImporter.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedNodeImporter.java Thu Oct 22 17:26:37 2009
@@ -17,7 +17,10 @@
package org.apache.jackrabbit.core.xml;
import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.util.ReferenceChangeTracker;
import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
import javax.jcr.RepositoryException;
import javax.jcr.nodetype.ConstraintViolationException;
@@ -33,12 +36,23 @@
* with all subsequent child <code>NodeInfo</code>s present below the protected
* parent until {@link #end(NodeImpl)} is called. The latter resets this importer
* and makes it available for another protected import.
- *
- * TODO: check if references properties can be handled with the info present
*/
public interface ProtectedNodeImporter {
/**
+ *
+ * @param session
+ * @param resolver
+ * @param isWorkspaceImport
+ * @param uuidBehavior
+ * @param referenceTracker
+ * @return
+ */
+ boolean init(JackrabbitSession session, NamePathResolver resolver,
+ boolean isWorkspaceImport, int uuidBehavior,
+ ReferenceChangeTracker referenceTracker);
+
+ /**
* Notifies this importer about the existience of a protected node that
* has either been created (NEW) or has been found to be existing.
* This importer implementation is in charge of evaluating the nature of
@@ -149,4 +163,13 @@
*/
void endChildInfo() throws RepositoryException;
+ /**
+ * Post processing protected reference properties underneith a parent
+ * node that has been handled by this importer.
+ * This method is called
+ * from {@link org.apache.jackrabbit.core.xml.Importer#end()}.
+ *
+ * @throws RepositoryException If an error occurs.
+ */
+ void processReferences() throws RepositoryException;
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedPropertyImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedPropertyImporter.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedPropertyImporter.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ProtectedPropertyImporter.java Thu Oct 22 17:26:37 2009
@@ -19,8 +19,11 @@
import javax.jcr.RepositoryException;
import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.util.ReferenceChangeTracker;
import org.apache.jackrabbit.core.state.NodeState;
import org.apache.jackrabbit.spi.QPropertyDefinition;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
+import org.apache.jackrabbit.api.JackrabbitSession;
/**
* <code>ProtectedPropertyImporter</code> is in charge of importing single
@@ -32,6 +35,18 @@
public interface ProtectedPropertyImporter {
/**
+ *
+ * @param session
+ * @param resolver
+ * @param isWorkspaceImport
+ * @param uuidBehavior
+ *@param referenceTracker @return
+ */
+ boolean init(JackrabbitSession session, NamePathResolver resolver,
+ boolean isWorkspaceImport, int uuidBehavior,
+ ReferenceChangeTracker referenceTracker);
+
+ /**
* Handles a single protected property.
*
* @param parent The affected parent node.
@@ -42,7 +57,8 @@
* <code>false</code> otherwise.
* @throws RepositoryException If an error occurs.
*/
- boolean handlePropInfo(NodeImpl parent, PropInfo protectedPropInfo, QPropertyDefinition def)
+ boolean handlePropInfo(NodeImpl parent, PropInfo protectedPropInfo,
+ QPropertyDefinition def)
throws RepositoryException;
/**
@@ -56,8 +72,17 @@
* <code>false</code> otherwise.
* @throws RepositoryException If an error occurs.
*/
- boolean handlePropInfo(NodeState parent, PropInfo protectedPropInfo, QPropertyDefinition def)
+ boolean handlePropInfo(NodeState parent, PropInfo protectedPropInfo,
+ QPropertyDefinition def)
throws RepositoryException;
+ /**
+ * Post processing protected reference properties. This method is called
+ * from {@link org.apache.jackrabbit.core.xml.Importer#end()}.
+ *
+ * @throws RepositoryException If an error occurs.
+ */
+ void processReferences() throws RepositoryException;
+
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java Thu Oct 22 17:26:37 2009
@@ -19,6 +19,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
+import java.util.ArrayList;
import javax.jcr.AccessDeniedException;
import javax.jcr.ImportUUIDBehavior;
@@ -34,6 +35,7 @@
import org.apache.jackrabbit.core.NodeImpl;
import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.config.ImportConfig;
import org.apache.jackrabbit.core.id.NodeId;
import org.apache.jackrabbit.core.security.authorization.Permission;
import org.apache.jackrabbit.core.util.ReferenceChangeTracker;
@@ -62,15 +64,16 @@
*/
private final ReferenceChangeTracker refTracker;
+ private final List<ProtectedNodeImporter> pnImporters = new ArrayList();
/**
- * Importer for protected nodes.
+ * Available importers for protected properties.
*/
- private final ProtectedNodeImporter pnImporter;
+ private final List<ProtectedPropertyImporter> ppImporters = new ArrayList();
/**
- * Importer for protected properties.
+ * Currently active importer for protected nodes.
*/
- private final ProtectedPropertyImporter ppImporter;
+ private ProtectedNodeImporter pnImporter = null;
/**
* Creates a new <code>SessionImporter</code> instance.
@@ -83,7 +86,7 @@
public SessionImporter(NodeImpl importTargetNode,
SessionImpl session,
int uuidBehavior) {
- this(importTargetNode, session, uuidBehavior, null, null);
+ this(importTargetNode, session, uuidBehavior, null);
}
/**
@@ -92,27 +95,47 @@
* @param importTargetNode the target node
* @param session session
* @param uuidBehavior the uuid behaviro
- * @param pnImporter importer for protected nodes
- * @param ppImporter importer for protected properties
+ * @param config
*/
public SessionImporter(NodeImpl importTargetNode, SessionImpl session,
- int uuidBehavior,
- ProtectedNodeImporter pnImporter,
- ProtectedPropertyImporter ppImporter) {
+ int uuidBehavior, ImportConfig config) {
this.importTargetNode = importTargetNode;
this.session = session;
this.uuidBehavior = uuidBehavior;
- this.ppImporter = ppImporter == null
- ? new DefaultProtectedPropertyImporter(session, session, false)
- : ppImporter;
- this.pnImporter = pnImporter == null
- ? new DefaultProtectedNodeImporter(session, session, false, uuidBehavior)
- : pnImporter;
refTracker = new ReferenceChangeTracker();
parents = new Stack<NodeImpl>();
parents.push(importTargetNode);
+
+ if (config != null) {
+ List<ProtectedNodeImporter> ln = config.getProtectedNodeImporters();
+ for (ProtectedNodeImporter pni : ln) {
+ if (pni.init(session, session, false, uuidBehavior, refTracker)) {
+ pnImporters.add(pni);
+ }
+ }
+ List<ProtectedPropertyImporter> lp = config.getProtectedPropertyImporters();
+ for (ProtectedPropertyImporter ppi : lp) {
+ if (ppi.init(session, session, false, uuidBehavior, refTracker)) {
+ ppImporters.add(ppi);
+ }
+ }
+ }
+
+ // missing config -> initialize defaults.
+ if (pnImporters.isEmpty()) {
+ ProtectedNodeImporter def = new DefaultProtectedNodeImporter();
+ if (def.init(session, session, false, uuidBehavior, refTracker)) {
+ pnImporters.add(def);
+ }
+ }
+ if (ppImporters.isEmpty()) {
+ DefaultProtectedPropertyImporter def = new DefaultProtectedPropertyImporter();
+ if (def.init(session, session, false, uuidBehavior, refTracker)) {
+ ppImporters.add(def);
+ }
+ }
}
/**
@@ -272,7 +295,9 @@
// parent node was skipped, skip this child node too
parents.push(null); // push null onto stack for skipped node
// notify the p-i-importer
- pnImporter.startChildInfo(nodeInfo, propInfos);
+ if (pnImporter != null) {
+ pnImporter.startChildInfo(nodeInfo, propInfos);
+ }
return;
}
@@ -284,11 +309,16 @@
// Notify the ProtectedNodeImporter about the start of a item
// tree that is protected by this parent. If it potentially is
// able to deal with it, notify it about the child node.
- if (pnImporter.start(parent)) {
- log.debug("Protected node -> delegated to ProtectedPropertyImporter");
- pnImporter.startChildInfo(nodeInfo, propInfos);
- } /* else: p-i-Importer isn't able to deal with the protected tree.
- skip the tree below the protected parent */
+ for (ProtectedNodeImporter pni : pnImporters) {
+ if (pni.start(parent)) {
+ log.debug("Protected node -> delegated to ProtectedPropertyImporter");
+ pnImporter = pni;
+ pnImporter.startChildInfo(nodeInfo, propInfos);
+ break;
+ } /* else: p-i-Importer isn't able to deal with the protected tree.
+ try next. and if none can handle the passed parent the
+ tree below will be skipped */
+ }
return;
}
@@ -375,10 +405,14 @@
log.debug("Skipping protected property " + pi.getName());
// notify the ProtectedPropertyImporter.
- if (ppImporter.handlePropInfo(node, pi, def)) {
- // TODO: deal with reference props within the imported tree?
- log.debug("Protected property -> delegated to ProtectedPropertyImporter");
- } // else: p-i-Importer isn't able to deal with this property
+ for (ProtectedPropertyImporter ppi : ppImporters) {
+ if (ppi.handlePropInfo(node, pi, def)) {
+ log.debug("Protected property -> delegated to ProtectedPropertyImporter");
+ break;
+ } /* else: p-i-Importer isn't able to deal with this property.
+ try next pp-importer */
+
+ }
} else {
// regular property -> create the property
createProperty(node, pi, def);
@@ -395,10 +429,16 @@
public void endNode(NodeInfo nodeInfo) throws RepositoryException {
NodeImpl parent = parents.pop();
if (parent == null) {
- pnImporter.endChildInfo();
+ if (pnImporter != null) {
+ pnImporter.endChildInfo();
+ }
} else if (parent.getDefinition().isProtected()) {
- pnImporter.end(parent);
- // TODO: deal with reference props within the imported tree?
+ if (pnImporter != null) {
+ pnImporter.end(parent);
+ // and reset the pnImporter field waiting for the next protected
+ // parent -> selecting again from available importers
+ pnImporter = null;
+ }
}
}
@@ -410,9 +450,24 @@
* adjust references that refer to uuid's which have been mapped to
* newly generated uuid's on import
*/
- Iterator iter = refTracker.getProcessedReferences();
+ // 1. let protected property/node importers handle protected ref-properties
+ // and (protected) properties underneith a protected parent node.
+ for (ProtectedPropertyImporter ppi : ppImporters) {
+ ppi.processReferences();
+ }
+ for (ProtectedNodeImporter pni : pnImporters) {
+ pni.processReferences();
+ }
+
+ // 2. regular non-protected properties.
+ Iterator<Object> iter = refTracker.getProcessedReferences();
while (iter.hasNext()) {
- Property prop = (Property) iter.next();
+ Object ref = iter.next();
+ if (!(ref instanceof Property)) {
+ continue;
+ }
+
+ Property prop = (Property) ref;
// being paranoid...
if (prop.getType() != PropertyType.REFERENCE
&& prop.getType() != PropertyType.WEAKREFERENCE) {
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java Thu Oct 22 17:26:37 2009
@@ -35,6 +35,7 @@
import org.apache.jackrabbit.core.HierarchyManager;
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.WorkspaceImpl;
+import org.apache.jackrabbit.core.config.ImportConfig;
import org.apache.jackrabbit.core.id.NodeId;
import org.apache.jackrabbit.core.id.PropertyId;
import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
@@ -66,7 +67,6 @@
private final WorkspaceImpl wsp;
private final SessionImpl session;
private final InternalVersionManager versionManager;
- private final NodeTypeRegistry ntReg;
private final HierarchyManager hierMgr;
private final BatchedItemOperations itemOps;
@@ -107,10 +107,40 @@
int uuidBehavior)
throws PathNotFoundException, ConstraintViolationException,
VersionException, LockException, RepositoryException {
+ this(parentPath, wsp, ntReg, uuidBehavior, null);
+ }
+
+ /**
+ * Creates a new <code>WorkspaceImporter</code> instance.
+ *
+ * @param parentPath target path where to add the imported subtree
+ * @param wsp the workspace to operate on
+ * @param ntReg the node type registry
+ * @param uuidBehavior flag that governs how incoming UUIDs are handled
+ * @param config import configuration.
+ * @throws PathNotFoundException if no node exists at
+ * <code>parentPath</code> or if the
+ * current session is not granted read
+ * access.
+ * @throws ConstraintViolationException if the node at
+ * <code>parentPath</code> is protected
+ * @throws VersionException if the node at
+ * <code>parentPath</code> is not
+ * checked-out
+ * @throws LockException if a lock prevents the addition of
+ * the subtree
+ * @throws RepositoryException if another error occurs
+ */
+ public WorkspaceImporter(Path parentPath,
+ WorkspaceImpl wsp,
+ NodeTypeRegistry ntReg,
+ int uuidBehavior,
+ ImportConfig config)
+ throws PathNotFoundException, ConstraintViolationException,
+ VersionException, LockException, RepositoryException {
this.wsp = wsp;
this.session = (SessionImpl) wsp.getSession();
this.versionManager = session.getInternalVersionManager();
- this.ntReg = ntReg;
this.uuidBehavior = uuidBehavior;
itemOps = new BatchedItemOperations(
@@ -128,6 +158,24 @@
parents = new Stack<NodeState>();
parents.push(importTarget);
+
+ // TODO: TOBEFIXED importer doesn't yet pass protected items to the configured importers.
+ // for the time being throw exception if an importer is configured that
+ // is expected to work with workspace import.
+ if (config != null) {
+ List<ProtectedNodeImporter> ln = config.getProtectedNodeImporters();
+ for (ProtectedNodeImporter pni : ln) {
+ if (pni.init(session, session, true, uuidBehavior, refTracker)) {
+ throw new UnsupportedOperationException("Workspace-Import of protected nodes: Not yet implement. ");
+ }
+ }
+ List<ProtectedPropertyImporter> lp = config.getProtectedPropertyImporters();
+ for (ProtectedPropertyImporter ppi : lp) {
+ if (ppi.init(session, session, true, uuidBehavior, refTracker)) {
+ throw new UnsupportedOperationException("Workspace-Import of protected properties: Not yet implement. ");
+ }
+ }
+ }
}
/**
@@ -660,7 +708,7 @@
* adjust references that refer to uuid's which have been mapped to
* newly gererated uuid's on import
*/
- Iterator iter = refTracker.getProcessedReferences();
+ Iterator<Object> iter = refTracker.getProcessedReferences();
while (iter.hasNext()) {
PropertyState prop = (PropertyState) iter.next();
// being paranoid...
Modified: jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd Thu Oct 22 17:26:37 2009
@@ -586,12 +586,10 @@
// User Management
// -----------------------------------------------------------------------------
-[rep:Authorizable] > mix:referenceable
+[rep:Authorizable] > mix:referenceable, nt:hierarchyNode
abstract
- + * (rep:Authorizable) = rep:Authorizable protected VERSION
- + * (rep:AuthorizableFolder) = rep:AuthorizableFolder protected VERSION
+ + * (nt:base) = nt:unstructured VERSION
- rep:principalName (STRING) protected mandatory
- - rep:groups (WEAKREFERENCE) protected multiple < 'rep:Group'
- * (UNDEFINED)
- * (UNDEFINED) multiple
@@ -603,11 +601,12 @@
- rep:password (STRING) protected mandatory
[rep:Group] > rep:Authorizable
+ - rep:members (WEAKREFERENCE) protected multiple < 'rep:Authorizable'
-[rep:AuthorizableFolder] > mix:referenceable
- + * (rep:Authorizable) = rep:User protected VERSION
- + * (rep:AuthorizableFolder) = rep:AuthorizableFolder protected VERSION
-
+[rep:AuthorizableFolder] > mix:referenceable, nt:hierarchyNode
+ + * (rep:Authorizable) = rep:User VERSION
+ + * (rep:AuthorizableFolder) = rep:AuthorizableFolder VERSION
+
// -----------------------------------------------------------------------------
// J A C K R A B B I T R E T E N T I O N M A N A G E M E N T
// -----------------------------------------------------------------------------
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AbstractUserTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AbstractUserTest.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AbstractUserTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AbstractUserTest.java Thu Oct 22 17:26:37 2009
@@ -34,7 +34,6 @@
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.util.Collections;
-import java.util.Iterator;
import java.util.Set;
import java.util.UUID;
@@ -45,6 +44,7 @@
protected UserManager userMgr;
+ @Override
protected void setUp() throws Exception {
super.setUp();
@@ -56,6 +56,22 @@
}
}
+ /**
+ * Conditional save if the userManager expects an extra save() call.
+ * NOTE: only works if changes are made with UserManager affect the passed
+ * session object (i.e. if the Session hold within the UserManager is
+ * the same as the passes Session s.
+ *
+ * @param s
+ * @throws RepositoryException
+ */
+ protected static void save(Session s) throws RepositoryException, NotExecutableException {
+ UserManager umgr = getUserManager(s);
+ if (!umgr.isAutoSave() && s.hasPendingChanges()) {
+ s.save();
+ }
+ }
+
protected static UserManager getUserManager(Session session) throws RepositoryException, NotExecutableException {
if (!(session instanceof JackrabbitSession)) {
throw new NotExecutableException();
@@ -70,7 +86,7 @@
}
protected static Subject buildSubject(Principal p) {
- return new Subject(true, Collections.singleton(p), Collections.EMPTY_SET, Collections.EMPTY_SET);
+ return new Subject(true, Collections.singleton(p), Collections.emptySet(), Collections.emptySet());
}
protected Principal getTestPrincipal() throws RepositoryException {
@@ -79,14 +95,13 @@
}
protected Principal getTestPrincipal(String name) throws RepositoryException {
- Principal p = new TestPrincipal(name);
- return p;
+ return new TestPrincipal(name);
}
protected String buildPassword(String uid, boolean createDigest) throws IllegalArgumentException {
if (createDigest) {
try {
- StringBuffer password = new StringBuffer();
+ StringBuilder password = new StringBuilder();
password.append("{").append(SecurityConstants.DEFAULT_DIGEST).append("}");
password.append(Text.digest(SecurityConstants.DEFAULT_DIGEST, uid.getBytes("UTF-8")));
return password.toString();
@@ -108,7 +123,7 @@
return new SimpleCredentials(uID, pw.toCharArray());
}
- protected static Set getPrincipalSetFromSession(Session session) throws NotExecutableException {
+ protected static Set<Principal> getPrincipalSetFromSession(Session session) throws NotExecutableException {
if (session instanceof SessionImpl) {
return ((SessionImpl) session).getSubject().getPrincipals();
} else {
@@ -123,13 +138,12 @@
return (User) auth;
}
// should never happen. An Session should always have a corresponding User.
- throw new RepositoryException("Unable to retrieve a User.");
+ throw new NotExecutableException("Unable to retrieve a User.");
}
protected Group getTestGroup(Session session) throws NotExecutableException, RepositoryException {
- Set principals = getPrincipalSetFromSession(session);
- for (Iterator it = principals.iterator(); it.hasNext();) {
- Authorizable auth = getUserManager(session).getAuthorizable((Principal) it.next());
+ for (Principal principal : getPrincipalSetFromSession(session)) {
+ Authorizable auth = getUserManager(session).getAuthorizable(principal);
if (auth != null && auth.isGroup()) {
return (Group) auth;
}
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AuthorizableTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AuthorizableTest.java?rev=828791&r1=828790&r2=828791&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AuthorizableTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AuthorizableTest.java Thu Oct 22 17:26:37 2009
@@ -16,11 +16,11 @@
*/
package org.apache.jackrabbit.api.security.user;
+import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.test.NotExecutableException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import javax.jcr.RepositoryException;
+import javax.jcr.Session;
import javax.jcr.Value;
import java.security.Principal;
import java.util.Arrays;
@@ -31,8 +31,6 @@
*/
public class AuthorizableTest extends AbstractUserTest {
- private static Logger log = LoggerFactory.getLogger(AuthorizableTest.class);
-
public void testGetId() throws NotExecutableException, RepositoryException {
User user = getTestUser(superuser);
assertNotNull(user.getID());
@@ -61,23 +59,26 @@
Value v = superuser.getValueFactory().createValue("Super User");
try {
auth.setProperty(propName, v);
+ save(superuser);
} catch (RepositoryException e) {
throw new NotExecutableException("Cannot test 'Authorizable.setProperty'.");
}
try {
boolean found = false;
- for (Iterator it = auth.getPropertyNames(); it.hasNext() && !found;) {
- found = propName.equals(it.next().toString());
+ for (Iterator<String> it = auth.getPropertyNames(); it.hasNext() && !found;) {
+ found = propName.equals(it.next());
}
assertTrue(found);
assertTrue(auth.hasProperty(propName));
assertTrue(auth.getProperty(propName).length == 1);
assertEquals(v, auth.getProperty(propName)[0]);
assertTrue(auth.removeProperty(propName));
+ save(superuser);
} finally {
// try to remove the property again even if previous calls failed.
auth.removeProperty(propName);
+ save(superuser);
}
}
@@ -89,22 +90,25 @@
Value[] v = new Value[] {superuser.getValueFactory().createValue("Super User")};
try {
auth.setProperty(propName, v);
+ save(superuser);
} catch (RepositoryException e) {
throw new NotExecutableException("Cannot test 'Authorizable.setProperty'.");
}
try {
boolean found = false;
- for (Iterator it = auth.getPropertyNames(); it.hasNext() && !found;) {
- found = propName.equals(it.next().toString());
+ for (Iterator<String> it = auth.getPropertyNames(); it.hasNext() && !found;) {
+ found = propName.equals(it.next());
}
assertTrue(found);
assertTrue(auth.hasProperty(propName));
assertEquals(Arrays.asList(v), Arrays.asList(auth.getProperty(propName)));
assertTrue(auth.removeProperty(propName));
+ save(superuser);
} finally {
// try to remove the property again even if previous calls failed.
auth.removeProperty(propName);
+ save(superuser);
}
}
@@ -116,19 +120,21 @@
Value v = superuser.getValueFactory().createValue("Super User");
try {
auth.setProperty(propName, v);
+ save(superuser);
} catch (RepositoryException e) {
throw new NotExecutableException("Cannot test 'Authorizable.setProperty'.");
}
try {
- for (Iterator it = auth.getPropertyNames(); it.hasNext();) {
- String name = it.next().toString();
+ for (Iterator<String> it = auth.getPropertyNames(); it.hasNext();) {
+ String name = it.next();
assertTrue(auth.hasProperty(name));
assertNotNull(auth.getProperty(name));
}
} finally {
// try to remove the property again even if previous calls failed.
auth.removeProperty(propName);
+ save(superuser);
}
}
@@ -155,12 +161,13 @@
i++;
}
assertFalse(auth.removeProperty(propName));
+ save(superuser);
}
public void testMemberOf() throws NotExecutableException, RepositoryException {
Authorizable auth = getTestUser(superuser);
- Iterator it = auth.memberOf();
+ Iterator<Group> it = auth.memberOf();
while (it.hasNext()) {
Object group = it.next();
assertTrue(group instanceof Group);
@@ -170,7 +177,7 @@
public void testDeclaredMemberOf() throws NotExecutableException, RepositoryException {
Authorizable auth = getTestUser(superuser);
- Iterator it = auth.declaredMemberOf();
+ Iterator<Group> it = auth.declaredMemberOf();
while (it.hasNext()) {
Object group = it.next();
assertTrue(group instanceof Group);
@@ -179,6 +186,8 @@
/**
* Removing an authorizable that is still listed as member of a group.
+ * @throws javax.jcr.RepositoryException
+ * @throws org.apache.jackrabbit.test.NotExecutableException
*/
public void testRemoveListedAuthorizable() throws RepositoryException, NotExecutableException {
String newUserId = null;
@@ -187,13 +196,16 @@
try {
Principal uP = getTestPrincipal();
User newUser = userMgr.createUser(uP.getName(), uP.getName());
+ save(superuser);
newUserId = newUser.getID();
newGroup = userMgr.createGroup(getTestPrincipal());
newGroup.addMember(newUser);
+ save(superuser);
// remove the new user that is still listed as member.
newUser.remove();
+ save(superuser);
} finally {
if (newUserId != null) {
Authorizable u = userMgr.getAuthorizable(newUserId);
@@ -207,6 +219,41 @@
if (newGroup != null) {
newGroup.remove();
}
+ save(superuser);
+ }
+ }
+
+ public void testRecreateUser() throws RepositoryException, NotExecutableException {
+ String id = "bla";
+ Authorizable auth = userMgr.getAuthorizable(id);
+ if (auth == null) {
+ auth = userMgr.createUser(id, id);
+ }
+ auth.remove();
+ save(superuser);
+
+ assertNull(userMgr.getAuthorizable(id));
+
+ // recreate the user using another session.
+ Session s2 = getHelper().getSuperuserSession();
+ User u2 = null;
+ try {
+ UserManager umgr = ((JackrabbitSession) s2).getUserManager();
+ assertNull(umgr.getAuthorizable(id));
+
+ // recreation must succeed
+ u2 = umgr.createUser(id, id);
+
+ // must be present with both session.
+ assertNotNull(umgr.getAuthorizable(id));
+ assertNotNull(userMgr.getAuthorizable(id));
+
+ } finally {
+ if (u2 != null) {
+ u2.remove();
+ save(s2);
+ }
+ s2.logout();
}
}
}