You are viewing a plain text version of this content. The canonical link for it is here.
Posted to slide-dev@jakarta.apache.org by un...@apache.org on 2004/08/09 14:05:29 UTC
cvs commit: jakarta-slide/src/share/org/apache/slide/structure ActionNode.java
unico 2004/08/09 05:05:29
Modified: src/webdav/server/org/apache/slide/webdav/util
AclConstants.java PropertyHelper.java
src/share/org/apache/slide/security SecurityImpl.java
src/webdav/server/org/apache/slide/webdav/method
AclMethod.java
src/share/org/apache/slide/structure ActionNode.java
Log:
add support for custom privileges thanks to Johan Stuyts (j.stuyts@hippo.nl):
- privilege change detection and actions cache invalidation
- "privilege-namespace" property holds optional namespace for privilege
Revision Changes Path
1.24 +5 -4 jakarta-slide/src/webdav/server/org/apache/slide/webdav/util/AclConstants.java
Index: AclConstants.java
===================================================================
RCS file: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/util/AclConstants.java,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -r1.23 -r1.24
--- AclConstants.java 5 Aug 2004 14:43:31 -0000 1.23
+++ AclConstants.java 9 Aug 2004 12:05:28 -0000 1.24
@@ -49,7 +49,7 @@
String P_GROUP_MEMBERSHIP = "group-membership";
String P_OWNER = "owner";
String P_MODIFICATIONUSER = "modificationuser";
- String P_CREATIONUSER = "creationuser";
+ String P_CREATIONUSER = "creationuser";
String P_SUPPORTED_PRIVILEGE_SET = "supported-privilege-set";
String P_CURRENT_USER_PRIVILEGE_SET = "current-user-privilege-set";
String P_ACL = "acl";
@@ -59,6 +59,7 @@
String P_PRIVILEGE_COLLECTION_SET = "privilege-collection-set";
String P_PRIVILEGE_MEMBER_SET = "privilege-member-set";
String P_PRIVILEGE_MEMBERSHIP = "privilege-membership";
+ String P_PRIVILEGE_NAMESPACE = "privilege-namespace";
String[] ACL_PROPERTIES = new String[] {
P_ALTERNATE_URI_SET,
1.80 +103 -40 jakarta-slide/src/webdav/server/org/apache/slide/webdav/util/PropertyHelper.java
Index: PropertyHelper.java
===================================================================
RCS file: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/util/PropertyHelper.java,v
retrieving revision 1.79
retrieving revision 1.80
diff -u -r1.79 -r1.80
--- PropertyHelper.java 5 Aug 2004 15:44:58 -0000 1.79
+++ PropertyHelper.java 9 Aug 2004 12:05:28 -0000 1.80
@@ -29,7 +29,6 @@
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -107,6 +106,8 @@
public final static String LOCKDISCOVERY_INCL_PRINCIPAL =
"lockdiscoveryIncludesPrincipalURL";
+ public final static String PRIVILEGE_NAMESPACE = "privilege-namespace";
+
private boolean lockdiscoveryIncludesPrincipalURL = true;
/**
@@ -1383,8 +1384,8 @@
transaction.addContent(groupoperation);
locktype.addContent(transaction);
} else {
- Element write = new Element(E_WRITE, DNSP);
- locktype.addContent(write);
+ Element write = new Element(E_WRITE, DNSP);
+ locktype.addContent(write);
}
Element lockscope = new Element(E_LOCKSCOPE, DNSP);
activelock.addContent(lockscope);
@@ -1535,23 +1536,12 @@
public XMLValue computeSupportedPrivilegeSet(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException, LockTokenNotFoundException, JDOMException {
Map actionAggregation = ((SecurityImpl)nsaToken.getSecurityHelper()).getActionAggregation();
Set rootSet = new HashSet(actionAggregation.keySet());
- Map work = new HashMap();
Iterator actions = actionAggregation.keySet().iterator();
while (actions.hasNext()) {
ActionNode a = (ActionNode)actions.next();
- Element sp = new Element(E_SUPPORTED_PRIVILEGE, DNSP);
- Element p = new Element(E_PRIVILEGE, DNSP);
- p.addContent(new Element(a.getPath().lastSegment(), DNSP));
- sp.addContent(p);
- work.put(a, sp);
- }
- actions = actionAggregation.keySet().iterator();
- while (actions.hasNext()) {
- ActionNode a = (ActionNode)actions.next();
Iterator aggregates = ((Set)actionAggregation.get(a)).iterator();
while (aggregates.hasNext()) {
ActionNode c = (ActionNode)aggregates.next();
- ((Element)work.get(a)).addContent((Element)work.get(c));
rootSet.remove(c);
}
}
@@ -1560,22 +1550,51 @@
p.addContent(new Element(E_ALL, DNSP));
rootSp.addContent(p);
Iterator roots = rootSet.iterator();
- while (roots.hasNext()) {
- rootSp.addContent((Element)work.get(roots.next()));
- }
+ addElementsForAggregatedActions(rootSp, roots, actionAggregation);
return new XMLValue(rootSp);
}
/**
+ * Build the tree of an action with all its aggregated actions for use in
+ * the result of <code>supported-privilege-set</code> queries.
+ *
+ * This method modifies <code>parentActionElement</code>.
+ *
+ * @param parentActionElement The action element to which to add the direct
+ * aggregated acttions to.
+ * @param aggregatedActions The direct aggregated actions.
+ * @param actionAggregation A map from an action to its direct aggregated
+ * actions.
+ */
+ private void addElementsForAggregatedActions(Element parentActionElement, Iterator aggregatedActions, Map actionAggregation) {
+ while (aggregatedActions.hasNext()) {
+ ActionNode a = (ActionNode)aggregatedActions.next();
+ Element sp = new Element(E_SUPPORTED_PRIVILEGE, DNSP);
+ Element p = new Element(E_PRIVILEGE, DNSP);
+ Namespace actionNamespace = a.getNamespace();
+ if (actionNamespace == null) {
+ actionNamespace = DNSP;
+ }
+ p.addContent(new Element(a.getPath().lastSegment(), actionNamespace));
+ addElementsForAggregatedActions(p, ((Set)actionAggregation.get(a)).iterator(), actionAggregation);
+ sp.addContent(p);
+ parentActionElement.addContent(sp);
+ }
+ }
+
+
+ /**
* Creates a <code><privilege></code> element containing an
* element with the given <code>privilegeName</code>.
*
* @param privilegeName the name of the privilege.
*
* @return the <code><privilege></code> element.
+ * @throws ServiceAccessException
+ * @throws RevisionDescriptorNotFoundException
*/
- private Element createPrivilege(String privilegeName) {
- return createPrivilege(privilegeName, true);
+ private Element createPrivilege(ActionNode privilege, Uri privilegeUri) throws RevisionDescriptorNotFoundException, ServiceAccessException {
+ return createPrivilege(privilege, true, privilegeUri);
}
/**
@@ -1588,16 +1607,25 @@
* otherwise the slide namespace.
*
* @return the <code><privilege></code> element.
+ * @throws ServiceAccessException
+ * @throws RevisionDescriptorNotFoundException
*/
- private Element createPrivilege(String privilegeName, boolean useDavNamespace) {
- Element privilege = new Element(E_PRIVILEGE, DNSP);
- Namespace namespace = DNSP;
- if ( ! useDavNamespace ) {
- namespace = NamespaceCache.SLIDE_NAMESPACE;
- }
- Element privilegeNameElement = new Element(privilegeName, namespace);
- privilege.addContent(privilegeNameElement);
- return privilege;
+ private Element createPrivilege(ActionNode privilege, boolean useDavNamespace, Uri privilegeUri) throws RevisionDescriptorNotFoundException, ServiceAccessException {
+ NodeRevisionNumber latestRevisionNumber = privilegeUri.getStore().retrieveRevisionDescriptors(privilegeUri).getLatestRevision();
+ NodeProperty privilegeNamespaceProperty = privilegeUri.getStore().retrieveRevisionDescriptor(privilegeUri, latestRevisionNumber).getProperty(PRIVILEGE_NAMESPACE, WebdavConstants.S_DAV);
+ Namespace privilegeNamespace = null;
+ if (privilegeNamespaceProperty != null && privilegeNamespaceProperty.getValue() instanceof String) {
+ privilegeNamespace = Namespace.getNamespace((String) privilegeNamespaceProperty.getValue());
+ } else {
+ privilegeNamespace = DNSP;
+ if ( ! useDavNamespace ) {
+ privilegeNamespace = NamespaceCache.SLIDE_NAMESPACE;
+ }
+ }
+ Element privilegeElement = new Element(E_PRIVILEGE, DNSP);
+ Element privilegeNameElement = new Element(privilege.getPath().lastSegment(), privilegeNamespace);
+ privilegeElement.addContent(privilegeNameElement);
+ return privilegeElement;
}
/**
@@ -1635,12 +1663,7 @@
Uri actionsPathUri = nsaToken.getUri(sToken, actionsPath);
ObjectNode actionsPathNode = actionsPathUri.getStore().retrieveObject(actionsPathUri);
Enumeration actions = actionsPathNode.enumerateChildren();
- while (actions.hasMoreElements()) {
- ActionNode aNode = ActionNode.getActionNode((String)actions.nextElement());
- if (security.hasPermission(sToken, object, aNode)) {
- xmlValue.add(createPrivilege(aNode.getPath().lastSegment()));
- }
- }
+ addGrantedActionsToPrivilegeSet(xmlValue, object, actions);
}
catch (ServiceAccessException e) {
throw e;
@@ -1652,6 +1675,35 @@
}
/**
+ * Build a set of privileges a subject has for an object for use in the
+ * result of <code>current-user-privilege-set</code> queries.
+ *
+ * This method modifies <code>xmlValue</code>.
+ *
+ * @param xmlValue The element to which to add the actions which have been
+ * granted to the subject.
+ * @param object The object for which to determine which actions have been
+ * granted.
+ * @param actions The URIs (as <code>String</code>s) of the actions to
+ * check.
+ */
+ private void addGrantedActionsToPrivilegeSet(XMLValue xmlValue, ObjectNode object, Enumeration actions) throws ServiceAccessException, ObjectNotFoundException, RevisionDescriptorNotFoundException {
+ while (actions.hasMoreElements()) {
+ Uri aNodeUri = nsaToken.getUri(sToken, (String)actions.nextElement());
+ ObjectNode oNode = aNodeUri.getStore().retrieveObject(aNodeUri);
+ if (oNode.hasChildren()) {
+ addGrantedActionsToPrivilegeSet(xmlValue, object, oNode.enumerateChildren());
+ } else {
+ ActionNode aNode = ActionNode.getActionNode(oNode.getUri());
+ if (nsaToken.getSecurityHelper().hasPermission(sToken, object, aNode)) {
+ xmlValue.add(createPrivilege(aNode, aNodeUri));
+ }
+ }
+ }
+ }
+
+
+ /**
* Returns an XMLValue containing the value of the
* <code><acl></code> property.
*
@@ -1784,14 +1836,25 @@
return principalElm;
}
- private Element createPrivilegeElement(String actionUri) {
+ private Element createPrivilegeElement(String actionUriAsString) throws RevisionDescriptorNotFoundException, ServiceAccessException {
Element privilegeElm = new Element(E_PRIVILEGE, DNSP);
- if (actionUri == ActionNode.ALL_URI) {
+ if (actionUriAsString.equals(ActionNode.ALL_URI)) {
Element allElm = new Element(E_ALL, DNSP);
privilegeElm.addContent(allElm);
}
else {
- Element actionElm = new Element(new UriPath(actionUri).lastSegment(), DNSP);
+ Uri actionUri = nsaToken.getUri(sToken, actionUriAsString);
+ NodeRevisionNumber latestRevisionNumber = actionUri.getStore().retrieveRevisionDescriptors(actionUri).getLatestRevision();
+ NodeProperty privilegeNamespace = actionUri.getStore().retrieveRevisionDescriptor(actionUri, latestRevisionNumber).getProperty(PRIVILEGE_NAMESPACE, WebdavConstants.S_DAV);
+ Namespace actionNamespace = null;
+ if (privilegeNamespace != null && privilegeNamespace.getValue() instanceof String) {
+ actionNamespace = Namespace.getNamespace((String) privilegeNamespace.getValue());
+ }
+ else {
+ actionNamespace = DNSP;
+ }
+
+ Element actionElm = new Element(new UriPath(actionUriAsString).lastSegment(), actionNamespace);
privilegeElm.addContent(actionElm);
}
return privilegeElm;
1.53 +271 -85 jakarta-slide/src/share/org/apache/slide/security/SecurityImpl.java
Index: SecurityImpl.java
===================================================================
RCS file: /home/cvs/jakarta-slide/src/share/org/apache/slide/security/SecurityImpl.java,v
retrieving revision 1.52
retrieving revision 1.53
diff -u -r1.52 -r1.53
--- SecurityImpl.java 5 Aug 2004 15:44:56 -0000 1.52
+++ SecurityImpl.java 9 Aug 2004 12:05:29 -0000 1.53
@@ -70,6 +70,7 @@
private static final String LOG_CHANNEL = SecurityImpl.class.getName();
private static final String PRIVILEGE_MEMBER_SET = "privilege-member-set";
+ private static final String PRIVILEGE_NAMESPACE = "privilege-namespace";
protected Logger logger;
@@ -94,7 +95,6 @@
this.rolesCache = new Hashtable();
aclInheritanceType = namespaceConfig.getAclInheritanceType();
logger = namespace.getLogger();
- loadActionsCache(namespace, namespaceConfig);
}
// ----------------------------------------------------- Instance Variables
@@ -127,6 +127,20 @@
private Map actionAggregation; // actionNode -> Set-of-aggregated-nodes (direct aggregates)
private Map actionAggregationClosure; // actionNode -> Set-of-aggregated-nodes (transitive closure)
+ /**
+ * If during the loading of the actions cache an error occurs, the cache
+ * state will remain 'not loaded'. To prevent that a new attempt is made to
+ * load the actions cache (which will probably fail too) each time the
+ * actions cache is accessed, this flag will be set.
+ */
+ private boolean hasActionsCacheLoadingFailed;
+
+ /**
+ * The actions that can modify objects in the repository. These are used
+ * to determine actions cache invalidation.
+ */
+ private Set modificationActions;
+
// ------------------------------------------------------- Security Methods
@@ -448,6 +462,7 @@
ActionNode action)
throws ServiceAccessException, AccessDeniedException,
ObjectNotFoundException {
+ determineActionsCacheInvalidation(object, action);
if (!hasPermission(object, subject, action)) {
throw new AccessDeniedException(object.getUri(), subject.getUri(),
@@ -469,6 +484,7 @@
* @throws ObjectNotFoundException
*/
public void checkPermission(SlideToken token, ObjectNode object, ActionNode action) throws ServiceAccessException, AccessDeniedException, ObjectNotFoundException {
+ determineActionsCacheInvalidation(object, action);
if (!hasPermission(token, object, action)) {
throw new AccessDeniedException(object.getUri(), getPrincipal(token).getUri(),
@@ -1049,67 +1065,6 @@
}
}
- private void loadActionsCache(Namespace namespace, NamespaceConfig namespaceConfig) {
- try {
- actionAggregation = new HashMap();
- actionAggregationClosure = new HashMap();
- String actionsPath = namespaceConfig.getActionsPath();
- Uri actionsPathUri = namespace.getUri(actionsPath);
- ObjectNode actionsPathNode = actionsPathUri.getStore().retrieveObject(actionsPathUri);
- Enumeration actions = actionsPathNode.enumerateChildren();
- while (actions.hasMoreElements()) {
- ActionNode aNode = ActionNode.getActionNode((String)actions.nextElement());
- Set directAggregates = getActionAggregates(aNode);
- actionAggregation.put(aNode, directAggregates);
- Set aClosure = new HashSet();
- aClosure.add(aNode);
- aClosure.addAll(directAggregates);
- actionAggregationClosure.put(aNode, aClosure);
- }
- Iterator keys = actionAggregationClosure.keySet().iterator();
- while (keys.hasNext()) {
- ActionNode aNode = (ActionNode)keys.next();
- Set aClosure = (Set)actionAggregationClosure.get(aNode);
- actionAggregationClosure.put(aNode, buildClosure(aClosure));
- }
- // log success
- if (logger.isEnabled(LOG_CHANNEL, Logger.DEBUG)) {
- logger.log("Action aggregations loaded successfully", LOG_CHANNEL, Logger.DEBUG);
- }
- if (logger.isEnabled(LOG_CHANNEL, Logger.DEBUG)) {
- logger.log("\n@@@ Actions aggregations", LOG_CHANNEL, Logger.DEBUG);
- Iterator i = actionAggregation.entrySet().iterator();
- while (i.hasNext()) {
- logger.log(" "+i.next(), LOG_CHANNEL, Logger.DEBUG);
- }
- logger.log("\n@@@ Action aggregations (transitive closure)", LOG_CHANNEL, Logger.DEBUG);
- i = actionAggregationClosure.entrySet().iterator();
- while (i.hasNext()) {
- logger.log(" "+i.next(), LOG_CHANNEL, Logger.DEBUG);
- }
- }
- }
- catch (Throwable e) {
- actionAggregation = null;
- actionAggregationClosure = null;
- }
- }
-
- private Set buildClosure(Set aClosure) {
- Set result = new HashSet(aClosure);
- int size = 0;
- while (result.size() > size) {
- size = result.size();
- Set newResult = new HashSet();
- Iterator i = result.iterator();
- while (i.hasNext()) {
- newResult.addAll((Set)actionAggregationClosure.get(i.next()));
- }
- result = newResult;
- }
- return result;
- }
-
/**
* Get the direct aggregates
*
@@ -1131,9 +1086,20 @@
else {
membersVal = new XMLValue((String)membersProp.getValue());
}
+ logger.log(membersVal.getHrefStrings(), LOG_CHANNEL, Logger.DEBUG);
Iterator mUris = membersVal.getHrefStrings().iterator();
while (mUris.hasNext()) {
- result.add(ActionNode.getActionNode((String)mUris.next()));
+ String uriAsString = (String)mUris.next();
+ Uri uri = new Uri(namespace, uriAsString);
+ NodeRevisionNumber latestRevisionNumber = aNodeUri.getStore().retrieveRevisionDescriptors(uri).getLatestRevision();
+ NodeProperty privilegeNamespace = aNodeUri.getStore().retrieveRevisionDescriptor(uri, latestRevisionNumber).getProperty(PRIVILEGE_NAMESPACE, "DAV:");
+ org.jdom.Namespace namespace = null;
+ if (privilegeNamespace != null && privilegeNamespace.getValue() instanceof String) {
+ namespace = org.jdom.Namespace.getNamespace((String) privilegeNamespace.getValue());
+ } else {
+ namespace = org.jdom.Namespace.getNamespace("DAV:");
+ }
+ result.add(ActionNode.getActionNode(uriAsString, namespace));
}
}
return result;
@@ -1150,27 +1116,18 @@
*
*/
public boolean matchAction(SlideToken token, ActionNode checkAction, ActionNode permAction) throws ServiceAccessException {
- if (permAction == ActionNode.ALL) {
+ if (permAction.equals(ActionNode.ALL)) {
return true;
}
- else {
- if (actionAggregationClosure != null) {
- Set permActionSet = (Set)actionAggregationClosure.get(permAction);
- if (permActionSet == null) {
- logger.log("Unknown action " + permAction.getUri() , LOG_CHANNEL, Logger.WARNING);
- return false;
- } else {
- return permActionSet.contains(checkAction);
- }
- }
- else {
- Uri u = namespace.getUri(token, checkAction.getUri());
- Store s = u.getStore();
- throw new ServiceAccessException(s, "Actions cache not loaded");
- }
+ Map actionAggregationClosure = getActionAggregationClosureImpl(token, checkAction.getUri());
+ Set permActionSet = (Set)actionAggregationClosure.get(permAction);
+ if (permActionSet == null) {
+ logger.log("Unknown action " + permAction.getUri() , LOG_CHANNEL, Logger.WARNING);
+ return false;
}
+ return permActionSet.contains(checkAction);
}
-
+
/**
* Return true, if-and-only-if checkSubject matches permSubject.
*
@@ -1265,6 +1222,235 @@
* @return a Map: actionNode -> Set-of-aggregated-nodes (direct aggregates)
*/
public Map getActionAggregation() {
- return Collections.unmodifiableMap(actionAggregation);
+ logger.log("Action aggregation being retrieved", LOG_CHANNEL, Logger.DEBUG);
+ return Collections.unmodifiableMap(getActionAggregationImpl());
+ }
+
+ /**
+ * Get the actions that modify objects in the repository. Which actions
+ * these are is defined in the configuration.
+ *
+ * @return The actions that modify objects in the repository.
+ */
+ private synchronized Set getModificationActions() {
+ if (this.modificationActions == null) {
+ Set modificationActions = new HashSet();
+ modificationActions.add(namespaceConfig.getBindMemberAction());
+ modificationActions.add(namespaceConfig.getCreateObjectAction());
+ modificationActions.add(namespaceConfig.getCreateRevisionContentAction());
+ modificationActions.add(namespaceConfig.getCreateRevisionMetadataAction());
+ modificationActions.add(namespaceConfig.getModifyRevisionContentAction());
+ modificationActions.add(namespaceConfig.getModifyRevisionMetadataAction());
+ modificationActions.add(namespaceConfig.getRemoveObjectAction());
+ modificationActions.add(namespaceConfig.getRemoveRevisionContentAction());
+ modificationActions.add(namespaceConfig.getRemoveRevisionMetadataAction());
+ modificationActions.add(namespaceConfig.getUnbindMemberAction());
+
+ modificationActions.remove(namespaceConfig.getDefaultAction());
+
+ this.modificationActions = Collections.unmodifiableSet(modificationActions);
+ }
+ return this.modificationActions;
+ }
+
+ /**
+ * Get whether an acion can modify objects in the repository.
+ *
+ * @param action The action for which to check whether it can modify
+ * objects in the repository.
+ * @return True if the actions can modify objects in the repository,
+ * false otherwise.
+ */
+ private boolean isModificationAction(ActionNode action) {
+ return getModificationActions().contains(action);
+ }
+
+ /**
+ * Determine whether an operation on an object in the repository
+ * invalidates the actions cache.
+ *
+ * @param object The subject of the operation.
+ * @param action The operation.
+ */
+ private void determineActionsCacheInvalidation(ObjectNode object, ActionNode action) {
+ if (object.getUri().startsWith(namespaceConfig.getActionsPath())) {
+ if (isModificationAction(action)) {
+ if (logger.isEnabled(Logger.DEBUG)) {
+ logger.log("Actions cache invalidated for operation " + action.getUri()
+ + " on action " + object.getUri(), LOG_CHANNEL, Logger.DEBUG);
+ }
+ invalidateActionsCache();
+ }
+ }
+ }
+
+ /**
+ * Invalidates the actions cache causing it to be reloaded the next time it
+ * is needed.
+ */
+ private synchronized void invalidateActionsCache() {
+ hasActionsCacheLoadingFailed = false;
+ actionAggregation = null;
+ actionAggregationClosure = null;
+ }
+
+ /**
+ * Populate the actions cache.
+ *
+ * @param namespace
+ * @param namespaceConfig
+ */
+ private synchronized void loadActionsCache(Namespace namespace, NamespaceConfig namespaceConfig) {
+ try {
+ actionAggregation = new HashMap();
+ actionAggregationClosure = new HashMap();
+ String actionsPath = namespaceConfig.getActionsPath();
+ Uri actionsPathUri = namespace.getUri(actionsPath);
+ ObjectNode actionsPathNode = actionsPathUri.getStore().retrieveObject(actionsPathUri);
+ Enumeration actions = actionsPathNode.enumerateChildren();
+ addActionLeafsToActionAggregation(actions);
+
+ Iterator keys = actionAggregationClosure.keySet().iterator();
+ while (keys.hasNext()) {
+ ActionNode aNode = (ActionNode)keys.next();
+ Set aClosure = (Set)actionAggregationClosure.get(aNode);
+ actionAggregationClosure.put(aNode, buildClosure(aClosure));
+ }
+ // log success
+ if (logger.isEnabled(LOG_CHANNEL, Logger.DEBUG)) {
+ logger.log("Action aggregations loaded successfully", LOG_CHANNEL, Logger.DEBUG);
+ }
+ if (logger.isEnabled(LOG_CHANNEL, Logger.DEBUG)) {
+ logger.log("\n@@@ Actions aggregations", LOG_CHANNEL, Logger.DEBUG);
+ Iterator i = actionAggregation.entrySet().iterator();
+ while (i.hasNext()) {
+ logger.log(" "+i.next(), LOG_CHANNEL, Logger.DEBUG);
+ }
+ logger.log("\n@@@ Action aggregations (transitive closure)", LOG_CHANNEL, Logger.DEBUG);
+ i = actionAggregationClosure.entrySet().iterator();
+ while (i.hasNext()) {
+ logger.log(" "+i.next(), LOG_CHANNEL, Logger.DEBUG);
+ }
+ }
+ }
+ catch (Throwable e) {
+ logger.log(e, LOG_CHANNEL, Logger.DEBUG);
+ actionAggregation = null;
+ actionAggregationClosure = null;
+ hasActionsCacheLoadingFailed = true;
+ }
+ }
+
+ /**
+ * Add children of <code>actions</code> which are leafs, collections
+ * without children, to the action cache. Recursively invoke this method
+ * for each child which is not a leaf.
+ *
+ * @param actions The collection containing child nodes.
+ * @throws SlideException
+ * @throws JDOMException
+ */
+ private synchronized void addActionLeafsToActionAggregation(Enumeration actions) throws SlideException, JDOMException {
+ while (actions.hasMoreElements()) {
+ Uri aNodeUri = namespace.getUri((String)actions.nextElement());
+ ObjectNode oNode = namespace.getStore(aNodeUri.getScope()).retrieveObject(aNodeUri);
+ if (oNode.hasChildren()) {
+ if (logger.isEnabled(Logger.DEBUG)) {
+ logger.log("Adding children of action " + oNode.getUri() + " to action aggregation", LOG_CHANNEL, Logger.DEBUG);
+ }
+ addActionLeafsToActionAggregation(oNode.enumerateChildren());
+ } else {
+ if (logger.isEnabled(Logger.DEBUG)) {
+ logger.log("Adding action " + oNode.getUri() + " to action aggregation", LOG_CHANNEL, Logger.DEBUG);
+ }
+ NodeRevisionNumber latestRevisionNumber = namespace.getStore(aNodeUri.getScope()).retrieveRevisionDescriptors(aNodeUri).getLatestRevision();
+ NodeProperty privilegeNamespace = namespace.getStore(aNodeUri.getScope()).retrieveRevisionDescriptor(aNodeUri, latestRevisionNumber).getProperty(PRIVILEGE_NAMESPACE, "DAV:");
+ ActionNode aNode;
+ org.jdom.Namespace actionNamespace;
+ if (privilegeNamespace != null && privilegeNamespace.getValue() instanceof String) {
+ actionNamespace = org.jdom.Namespace.getNamespace((String) privilegeNamespace.getValue());
+ } else {
+ actionNamespace = org.jdom.Namespace.getNamespace("DAV:");
+ }
+ aNode = ActionNode.getActionNode(oNode.getUri(), actionNamespace);
+ Set directAggregates = getActionAggregates(aNode);
+ actionAggregation.put(aNode, directAggregates);
+ Set aClosure = new HashSet();
+ aClosure.add(aNode);
+ aClosure.addAll(directAggregates);
+ actionAggregationClosure.put(aNode, aClosure);
+ }
+ }
+ }
+
+ /**
+ * Determines the complete set of children and grandchildren of an action.
+ * These are the children/grandchildren determined by the
+ * <code>D:privilege-member-set</code> hierarchy.
+ *
+ * @param aClosure A collection containing the action and its known
+ * children and grandchildren.
+ * @return A collection containing the action, its known and additionally
+ * found children and grandchildren.
+ */
+ private synchronized Set buildClosure(Set aClosure) {
+ Set result = new HashSet(aClosure);
+ int size = 0;
+ while (result.size() > size) {
+ size = result.size();
+ Set newResult = new HashSet();
+ Iterator i = result.iterator();
+ while (i.hasNext()) {
+ Object member = i.next();
+ Set membersOfMember = (Set)actionAggregationClosure.get(member);
+ if (membersOfMember != null) {
+ newResult.addAll(membersOfMember);
+ }
+ }
+ result = newResult;
+ }
+ return result;
+ }
+
+ /**
+ * Get a map which maps an action to its direct aggregated actions.
+ *
+ * If the actions cache is not loaded, an attempt will be made to load the
+ * actions cache.
+ *
+ * @return A map from actions to their aggregated actions, or and empty map
+ * if loading of the actions cache failed.
+ */
+ private synchronized Map getActionAggregationImpl() {
+ if (this.actionAggregation == null && !this.hasActionsCacheLoadingFailed) {
+ loadActionsCache(this.namespace, this.namespaceConfig);
+ }
+ if (this.hasActionsCacheLoadingFailed) {
+ logger.log("actionAggregation retrieved but cache didn't load successfully" , LOG_CHANNEL, Logger.WARNING);
+ return new HashMap();
+ }
+ return this.actionAggregation;
+ }
+
+ /**
+ * Get a map which maps an action to all its aggregated actions.
+ *
+ * If the actions cache is not loaded, an attempt will be made to load the
+ * actions cache.
+ *
+ * @return A map from actions to their aggregated actions.
+ * @throws ServiceAccessException Indicates the loading of the actions
+ * cache failed.
+ */
+ private synchronized Map getActionAggregationClosureImpl(SlideToken token, String uri) throws ServiceAccessException {
+ if (this.actionAggregationClosure == null && !this.hasActionsCacheLoadingFailed) {
+ loadActionsCache(this.namespace, this.namespaceConfig);
+ }
+ if (this.hasActionsCacheLoadingFailed) {
+ Uri u = this.namespace.getUri(token, uri);
+ Store s = u.getStore();
+ throw new ServiceAccessException(s, "Actions cache not loaded");
+ }
+ return this.actionAggregationClosure;
}
}
1.45 +59 -12 jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/AclMethod.java
Index: AclMethod.java
===================================================================
RCS file: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/AclMethod.java,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -r1.44 -r1.45
--- AclMethod.java 3 Aug 2004 09:37:48 -0000 1.44
+++ AclMethod.java 9 Aug 2004 12:05:29 -0000 1.45
@@ -28,12 +28,16 @@
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
-
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.ServiceAccessException;
-import org.apache.slide.event.EventDispatcher;
+import org.apache.slide.common.SlideException;
+import org.apache.slide.common.Uri;
+import org.apache.slide.content.NodeProperty;
+import org.apache.slide.content.NodeRevisionDescriptor;
+import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.security.NodePermission;
import org.apache.slide.structure.ActionNode;
+import org.apache.slide.structure.ObjectNode;
import org.apache.slide.structure.SubjectNode;
import org.apache.slide.webdav.WebdavException;
import org.apache.slide.webdav.WebdavServletConfig;
@@ -41,14 +45,15 @@
import org.apache.slide.webdav.util.AclConstants;
import org.apache.slide.webdav.util.PreconditionViolationException;
import org.apache.slide.webdav.util.ViolatedPrecondition;
+import org.apache.slide.webdav.util.WebdavConstants;
import org.apache.slide.webdav.util.WebdavStatus;
+import org.apache.slide.event.EventDispatcher;
import org.jdom.Element;
import org.jdom.JDOMException;
/**
* ACL method.
- *
*/
public class AclMethod extends AbstractWebdavMethod implements AclConstants, WriteMethod {
@@ -102,9 +107,14 @@
} catch (IOException x) {}
throw new WebdavException(e.getStatusCode());
}
+ catch (SlideException e) {
+ int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
+ sendError( statusCode, e );
+ throw new WebdavException( statusCode );
+ }
}
- private List createNodePermissionList( Element aceElm ) throws JDOMException, PreconditionViolationException {
+ private List createNodePermissionList( Element aceElm ) throws PreconditionViolationException, SlideException, JDOMException {
List result = new ArrayList();
String objectUri = resourcePath;
String subjectUri = null;
@@ -206,17 +216,55 @@
);
}
- private String createActionUri(Element privilegeElm) throws JDOMException, PreconditionViolationException {
- String privilege = ((Element)privilegeElm.getChildren().get(0)).getName();
- if (E_ALL.equals(privilege)) {
+ private String createActionUri(Element privilegeElm) throws JDOMException, PreconditionViolationException, SlideException {
+ Element privilegeChildElm = (Element)privilegeElm.getChildren().get(0);
+ String privilegeName = privilegeChildElm.getName();
+ String privilegeNamespace = privilegeChildElm.getNamespaceURI();
+ if (E_ALL.equals(privilegeName) && S_DAV.equals(privilegeNamespace)) {
return ActionNode.ALL_URI;
}
else {
- return token.getNamespaceConfig().getActionsPath()+"/"+privilege;
+ ObjectNode actions = structure.retrieve(slideToken, token.getNamespaceConfig().getActionsPath());
+ ObjectNode action = findAction(actions.getChildren().iterator(), privilegeName, privilegeNamespace);
+ return action.getUri();
}
}
/**
+ * Find an action in the repository based on its simple name and its namespace.
+ *
+ * @param actionsIterator An iterator over the actions collection to search in.
+ * @param privilegeName The simple name of the action.
+ * @param privilegeNamespace The name space of the action.
+ * @return The action having the simple name and namespace.
+ * @throws SlideException There was a problem accessing the actions in the repository.
+ */
+ private ObjectNode findAction(Iterator actionsIterator, String privilegeName, String privilegeNamespace) throws SlideException {
+ ObjectNode result = null;
+ while (result == null && actionsIterator.hasNext()) {
+ String aUriAsString = (String) actionsIterator.next();
+ ObjectNode aNode = structure.retrieve(slideToken, aUriAsString);
+ if (aNode.hasChildren()) {
+ result = findAction(aNode.getChildren().iterator(), privilegeName, privilegeNamespace);
+ }
+ else {
+ Uri aUri = token.getUri(slideToken, aUriAsString);
+ NodeRevisionDescriptors nrds = aUri.getStore().retrieveRevisionDescriptors(aUri);
+ NodeRevisionDescriptor latestNrd = aUri.getStore().retrieveRevisionDescriptor(aUri, nrds.getLatestRevision());
+ NodeProperty aNamespaceAsNode = latestNrd.getProperty(AclConstants.P_PRIVILEGE_NAMESPACE, WebdavConstants.S_DAV);
+ String aNamespace = aNamespaceAsNode == null ? null : aNamespaceAsNode.getValue().toString();
+ String aUriLastSegment = aUriAsString.substring(aUriAsString.lastIndexOf('/') + 1);
+ if (aUriLastSegment.equals(privilegeName)
+ && ((aNamespace != null && privilegeNamespace.equals(aNamespace))
+ || (aNamespace == null && privilegeNamespace.equals(WebdavConstants.S_DAV)))) {
+ result = aNode;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
* Method checkPreconditions
*
* @throws PreconditionViolationException
@@ -267,4 +315,3 @@
}
}
}
-
1.10 +74 -14 jakarta-slide/src/share/org/apache/slide/structure/ActionNode.java
Index: ActionNode.java
===================================================================
RCS file: /home/cvs/jakarta-slide/src/share/org/apache/slide/structure/ActionNode.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- ActionNode.java 28 Jul 2004 09:34:35 -0000 1.9
+++ ActionNode.java 9 Aug 2004 12:05:29 -0000 1.10
@@ -24,10 +24,18 @@
package org.apache.slide.structure;
import java.util.Vector;
+import org.apache.slide.content.NodeProperty.NamespaceCache;
+import org.jdom.Namespace;
/**
- * Action node class.
- *
+ * Action node class. The namespace is used to distinguish actions with the
+ * same simple name.
+ *
+ * Although this class has a <code>namespace</code> attribute the equality of
+ * two <code>ActionNode</code>s can still be determined by comparing their
+ * URIs. Therefore this class does not override <code>equals(Object)</code>
+ * from <code>ObjectNode</code>.
+ *
* @version $Revision$
*/
public class ActionNode extends ObjectNode {
@@ -36,8 +44,13 @@
public static final String DEFAULT_URI = "default";
public static final String ALL_URI = "all";
- public static final ActionNode DEFAULT = new ActionNode(DEFAULT_URI);
- public static final ActionNode ALL = new ActionNode(ALL_URI);
+ public static final ActionNode DEFAULT = new ActionNode(DEFAULT_URI, NamespaceCache.DEFAULT_NAMESPACE);
+ public static final ActionNode ALL = new ActionNode(ALL_URI, NamespaceCache.DEFAULT_NAMESPACE);
+
+ /**
+ * The namespace of the action.
+ */
+ private Namespace namespace;
// ----------------------------------------------------------- Constructors
@@ -67,17 +80,64 @@
super(uuri, bindings, parentBindings, links);
}
- public static String getActionUri(String actionUri) {
- if (ActionNode.ALL_URI != actionUri && ActionNode.ALL_URI.equals(actionUri)) {
- return ActionNode.ALL_URI;
- }
- return actionUri;
+ /**
+ * Create an <code>ActionNode</code> with a namespace extracted from the
+ * <code>privilege-namespace</code> property.
+ *
+ * @param uri The Slide-internal URI of the ActionNode.
+ * @param namespace The namespace of the action.
+ */
+ public ActionNode(String uri, Namespace namespace) {
+ super(uri);
+ this.namespace = namespace;
}
-
+
+ /**
+ * Create an <code>ActionNode</code> without a namespace. If retrieval of
+ * the namespace is attempted on the result an exception will be thrown.
+ *
+ * This method is not required to return a unique instance each time it is
+ * invoked.
+ *
+ * @param actionUri The URI which uniquely identifies the <code>ActionNode</code>.
+ * @return An <code>ActionNode</code> without a namespace.
+ */
public static ActionNode getActionNode(String actionUri) {
- if (ActionNode.ALL_URI == actionUri || ActionNode.ALL_URI.equals(actionUri)) {
+ if (ActionNode.ALL_URI.equals(actionUri)) {
return ActionNode.ALL;
}
return new ActionNode(actionUri);
+ }
+
+ /**
+ * Create an ActionNode with a namespace.
+ *
+ * This method is not required to return a unique instance each time it is
+ * invoked.
+ *
+ * @param The URI which uniquely identifies the <code>ActionNode</code>.
+ * @param namespace The namespace of the <code>ActionNode</code>.
+ * @return An <code>ActionNode</code> with a namespace.
+ */
+ public static ActionNode getActionNode(String actionUri, Namespace namespace) {
+ if (ActionNode.ALL_URI.equals(actionUri) && NamespaceCache.DEFAULT_NAMESPACE.equals(namespace)) {
+ return ActionNode.ALL;
+ }
+ return new ActionNode(actionUri, namespace);
+ }
+
+ /**
+ * Get the namespace. If the <code>ActionNode</code> was constructed
+ * without a namespace, an exception will be thrown.
+ *
+ * @return The namespace of the <code>ActionNode</code>.
+ * @throws IllegalStateException The <code>ActionNode</code> was
+ * constructed without a namespace.
+ */
+ public Namespace getNamespace() {
+ if (this.namespace == null) {
+ throw new IllegalStateException("Namespace retrieved without being specified");
+ }
+ return this.namespace;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: slide-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: slide-dev-help@jakarta.apache.org