You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2011/04/06 15:48:24 UTC
svn commit: r1089453 - in /jackrabbit/branches/2.2: ./
jackrabbit-core/src/main/java/org/apache/jackrabbit/core/
jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/
jackrabbit-core/src/main/java/org/apache/jackrabbit/co...
Author: jukka
Date: Wed Apr 6 13:48:24 2011
New Revision: 1089453
URL: http://svn.apache.org/viewvc?rev=1089453&view=rev
Log:
2.2: Merged revisions 1087304 and 1089436 (JCR-2890)
Modified:
jackrabbit/branches/2.2/ (props changed)
jackrabbit/branches/2.2/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java
jackrabbit/branches/2.2/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java
jackrabbit/branches/2.2/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java
Propchange: jackrabbit/branches/2.2/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Wed Apr 6 13:48:24 2011
@@ -2,4 +2,4 @@
/jackrabbit/sandbox/JCR-1456:774917-886178
/jackrabbit/sandbox/JCR-2170:812417-816332
/jackrabbit/sandbox/tripod-JCR-2209:795441-795863
-/jackrabbit/trunk:1038201,1038203,1038205,1038657,1039064,1039347,1039408,1039422-1039423,1039888,1039946,1040033,1040090,1040459,1040601,1040606,1040661,1040958,1041379,1041439,1041761,1042643,1042647,1042978-1042982,1043084-1043086,1043088,1043343,1043357-1043358,1043430,1043554,1043616,1043618,1043637,1043656,1043893,1043897,1044239,1044312,1044451,1044613,1049473,1049491,1049514,1049518,1049520,1049859,1049870,1049874,1049878,1049880,1049883,1049889,1049891,1049894-1049895,1049899-1049901,1049909-1049911,1049915-1049916,1049919,1049923,1049925,1049931,1049936,1049939,1050212,1050298,1050346,1050551,1055068,1055070-1055071,1055116-1055117,1055127,1055134,1055164,1055498,1060431,1060434,1060753,1063756,1065599,1065622,1066059,1066071,1069831,1071562,1071573,1071680,1074140,1079314,1079317,1089032
+/jackrabbit/trunk:1038201,1038203,1038205,1038657,1039064,1039347,1039408,1039422-1039423,1039888,1039946,1040033,1040090,1040459,1040601,1040606,1040661,1040958,1041379,1041439,1041761,1042643,1042647,1042978-1042982,1043084-1043086,1043088,1043343,1043357-1043358,1043430,1043554,1043616,1043618,1043637,1043656,1043893,1043897,1044239,1044312,1044451,1044613,1049473,1049491,1049514,1049518,1049520,1049859,1049870,1049874,1049878,1049880,1049883,1049889,1049891,1049894-1049895,1049899-1049901,1049909-1049911,1049915-1049916,1049919,1049923,1049925,1049931,1049936,1049939,1050212,1050298,1050346,1050551,1055068,1055070-1055071,1055116-1055117,1055127,1055134,1055164,1055498,1060431,1060434,1060753,1063756,1065599,1065622,1066059,1066071,1069831,1071562,1071573,1071680,1074140,1079314,1079317,1087304,1089032,1089436
Modified: jackrabbit/branches/2.2/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.2/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java?rev=1089453&r1=1089452&r2=1089453&view=diff
==============================================================================
--- jackrabbit/branches/2.2/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java (original)
+++ jackrabbit/branches/2.2/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java Wed Apr 6 13:48:24 2011
@@ -105,6 +105,27 @@ class SystemSession extends SessionImpl
return new SystemAccessManager();
}
+ /**
+ * Creates and returns a new <em>system</em> session for the
+ * given workspace.
+ *
+ * @param workspaceName workspace name,
+ * or <code>null</code> for the default workspace
+ */
+ @Override
+ public SessionImpl createSession(String workspaceName)
+ throws RepositoryException {
+ if (workspaceName == null) {
+ WorkspaceManager wm = repositoryContext.getWorkspaceManager();
+ workspaceName = wm.getDefaultWorkspaceName();
+ }
+
+ RepositoryImpl repository = repositoryContext.getRepository();
+ WorkspaceConfig wspConfig =
+ repository.getWorkspaceInfo(workspaceName).getConfig();
+ return create(repositoryContext, wspConfig);
+ }
+
//--------------------------------------------------------< inner classes >
/**
* An access manager that grants access to everything.
Modified: jackrabbit/branches/2.2/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.2/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java?rev=1089453&r1=1089452&r2=1089453&view=diff
==============================================================================
--- jackrabbit/branches/2.2/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java (original)
+++ jackrabbit/branches/2.2/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java Wed Apr 6 13:48:24 2011
@@ -23,12 +23,14 @@ import org.apache.jackrabbit.core.securi
import org.apache.jackrabbit.core.security.authorization.AccessControlModifications;
import org.apache.jackrabbit.core.security.authorization.AccessControlObserver;
import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.util.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
+import javax.jcr.Session;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.ObservationManager;
@@ -64,11 +66,6 @@ public class EntryCollector extends Acce
protected final NodeId rootID;
private final PrivilegeRegistry privilegeRegistry;
-
- /**
- * Standard JCR name form of the {@link #N_POLICY} constant.
- */
- private final String repPolicyName;
/**
*
@@ -81,7 +78,6 @@ public class EntryCollector extends Acce
this.rootID = rootID;
privilegeRegistry = new PrivilegeRegistry(systemSession);
- repPolicyName = systemSession.getJCRName(N_POLICY);
ObservationManager observationMgr = systemSession.getWorkspace().getObservationManager();
/*
@@ -205,102 +201,191 @@ public class EntryCollector extends Acce
return ((NodeImpl) systemSession.getItemManager().getItem(nodeId));
}
- //------------------------------------------------------------< private >---
-
- private static NodeId accessControlledIdFromAclNode(Node aclNode) throws RepositoryException {
- return ((NodeImpl) aclNode.getParent()).getNodeId();
- }
-
- private static NodeId accessControlledIdFromAceNode(Node aceNode) throws RepositoryException {
- return ((NodeImpl) aceNode.getParent().getParent()).getNodeId();
- }
-
- private static void addModification(NodeId accessControllNodeId, int modType,
- Map<NodeId,Integer> modMap) {
- if (modMap.containsKey(accessControllNodeId)) {
- // update modMap
- modMap.put(accessControllNodeId, modType | modMap.get(accessControllNodeId));
- } else {
- modMap.put(accessControllNodeId, modType);
- }
- }
-
//------------------------------------------------------< EventListener >---
+
/**
- * Collect is of access controlled nodes that are effected by access control
- * modification together with the corresponding modification type and
- * finally inform listeners about the modifications.
+ * Collects access controlled nodes that are effected by access control
+ * changes together with the corresponding modification types, and
+ * notifies access control listeners about the modifications.
*
* @param events
*/
public void onEvent(EventIterator events) {
- /* map of access-controlled nodeId to type of ac modification */
- Map<NodeId,Integer> modMap = new HashMap<NodeId,Integer>();
-
- // collect the ids of all access controlled nodes that have been affected
- // by the events and thus need their cache entries updated or cleared.
- while (events.hasNext()) {
+ try {
+ // JCR-2890: We need to use a fresh new session here to avoid
+ // deadlocks caused by concurrent threads possibly using the
+ // systemSession instance for other purposes.
+ String workspaceName = systemSession.getWorkspace().getName();
+ Session session = systemSession.createSession(workspaceName);
try {
- Event ev = events.nextEvent();
- String identifier = ev.getIdentifier();
- String path = ev.getPath();
+ // Sift through the events to find access control modifications
+ ACLEventSieve sieve = new ACLEventSieve(session);
+ sieve.siftEvents(events);
+
+ // Notify listeners and eventually clean up internal caches
+ AccessControlModifications<NodeId> mods =
+ sieve.getModifications();
+ if (!mods.getNodeIdentifiers().isEmpty()) {
+ notifyListeners(mods);
+ }
+ } finally {
+ session.logout();
+ }
+ } catch (RepositoryException e) {
+ log.error("Failed to process access control modifications", e);
+ }
+ }
- switch (ev.getType()) {
+ /**
+ * Private utility class for sifting through observation events on
+ * ACL, ACE and Policy nodes to find out the nodes whose access controls
+ * have changed. Used by the {@link EntryCollector#onEvent(EventIterator)}
+ * method.
+ */
+ private static class ACLEventSieve {
+
+ /** Session with system privileges. */
+ private final Session session;
+
+ /**
+ * Standard JCR name form of the
+ * {@link AccessControlConstants#N_POLICY} constant.
+ */
+ private final String repPolicyName;
+
+ /**
+ * Map of access-controlled nodeId to type of access control modification.
+ */
+ private final Map<NodeId, Integer> modMap =
+ new HashMap<NodeId,Integer>();
+
+ public ACLEventSieve(Session session) throws RepositoryException {
+ this.session = session;
+ Name repPolicy = AccessControlConstants.N_POLICY;
+ this.repPolicyName =
+ session.getNamespacePrefix(repPolicy.getNamespaceURI())
+ + ":" + repPolicy.getLocalName();
+ }
+
+ /**
+ * Collects the identifiers of all access controlled nodes that have
+ * been affected by the events, and thus need their cache entries
+ * updated or cleared.
+ *
+ * @param events access control modification events
+ */
+ public void siftEvents(EventIterator events) {
+ while (events.hasNext()) {
+ Event event = events.nextEvent();
+ try {
+ switch (event.getType()) {
case Event.NODE_ADDED:
- NodeImpl n = (NodeImpl) systemSession.getNodeByIdentifier(identifier);
- if (n.isNodeType(NT_REP_ACL)) {
- // a new ACL was added -> use the added node to update
- // the cache.
- addModification(accessControlledIdFromAclNode(n), POLICY_ADDED, modMap);
- } else if (n.isNodeType(NT_REP_ACE)) {
- // a new ACE was added -> use the parent node (acl)
- // to update the cache.
- addModification(accessControlledIdFromAceNode(n), POLICY_MODIFIED, modMap);
- } /* else: some other node added below an access controlled
- parent node -> not interested. */
+ siftNodeAdded(event.getIdentifier());
break;
case Event.NODE_REMOVED:
- String parentPath = Text.getRelativeParent(path, 1);
- if (systemSession.nodeExists(parentPath)) {
- NodeImpl parent = (NodeImpl) systemSession.getNode(parentPath);
- if (repPolicyName.equals(Text.getName(path))){
- // the complete acl was removed -> clear cache entry
- addModification(parent.getNodeId(), POLICY_REMOVED, modMap);
- } else if (parent.isNodeType(NT_REP_ACL)) {
- // an ace was removed -> refresh cache for the
- // containing access control list upon next access
- addModification(accessControlledIdFromAclNode(parent), POLICY_MODIFIED, modMap);
- } /* else:
- a) some other child node of an access controlled
- node -> not interested.
- b) a child node of an ACE. not relevant for this
- implementation -> ignore
- */
- } else {
- log.debug("Cannot process NODE_REMOVED event. Parent " + parentPath + " doesn't exist (anymore).");
- }
+ siftNodeRemoved(event.getPath());
break;
case Event.PROPERTY_CHANGED:
- // test if the changed prop belongs to an ACE
- NodeImpl parent = (NodeImpl) systemSession.getNodeByIdentifier(identifier);
- if (parent.isNodeType(NT_REP_ACE)) {
- addModification(accessControlledIdFromAceNode(parent), POLICY_MODIFIED, modMap);
- } /* some other property below an access controlled node
- changed -> not interested. (NOTE: rep:ACL doesn't
- define any properties. */
+ siftPropertyChanged(event.getIdentifier());
break;
default:
// illegal event-type: should never occur. ignore
+ }
+ } catch (RepositoryException e) {
+ // should not get here
+ log.error("Failed to process ACL event: " + event, e);
}
- } catch (RepositoryException e) {
- // should not get here
- log.error("Internal error: ", e);
}
}
- if (!modMap.isEmpty()) {
- // notify listeners and eventually clean up internal caches.
- notifyListeners(new AccessControlModifications<NodeId>(modMap));
+ /**
+ * Returns the access control modifications collected from
+ * related observation events.
+ *
+ * @return access control modifications
+ */
+ public AccessControlModifications<NodeId> getModifications() {
+ return new AccessControlModifications<NodeId>(modMap);
+ }
+
+ private void siftNodeAdded(String identifier)
+ throws RepositoryException {
+ NodeImpl n = (NodeImpl) session.getNodeByIdentifier(identifier);
+ if (n.isNodeType(EntryCollector.NT_REP_ACL)) {
+ // a new ACL was added -> use the added node to update
+ // the cache.
+ addModification(
+ accessControlledIdFromAclNode(n),
+ AccessControlObserver.POLICY_ADDED);
+ } else if (n.isNodeType(EntryCollector.NT_REP_ACE)) {
+ // a new ACE was added -> use the parent node (acl)
+ // to update the cache.
+ addModification(
+ accessControlledIdFromAceNode(n),
+ AccessControlObserver.POLICY_MODIFIED);
+ } /* else: some other node added below an access controlled
+ parent node -> not interested. */
+ }
+
+ private void siftNodeRemoved(String path) throws RepositoryException {
+ String parentPath = Text.getRelativeParent(path, 1);
+ if (session.nodeExists(parentPath)) {
+ NodeImpl parent = (NodeImpl) session.getNode(parentPath);
+ if (repPolicyName.equals(Text.getName(path))){
+ // the complete ACL was removed -> clear cache entry
+ addModification(
+ parent.getNodeId(),
+ AccessControlObserver.POLICY_REMOVED);
+ } else if (parent.isNodeType(EntryCollector.NT_REP_ACL)) {
+ // an ace was removed -> refresh cache for the
+ // containing access control list upon next access
+ addModification(
+ accessControlledIdFromAclNode(parent),
+ AccessControlObserver.POLICY_MODIFIED);
+ } /* else:
+ a) some other child node of an access controlled
+ node -> not interested.
+ b) a child node of an ACE. not relevant for this
+ implementation -> ignore
+ */
+ } else {
+ log.debug("Cannot process NODE_REMOVED event."
+ + " Parent {} doesn't exist (anymore).",
+ parentPath);
+ }
+ }
+
+ private void siftPropertyChanged(String identifier)
+ throws RepositoryException {
+ // test if the changed prop belongs to an ACE
+ NodeImpl parent = (NodeImpl) session.getNodeByIdentifier(identifier);
+ if (parent.isNodeType(EntryCollector.NT_REP_ACE)) {
+ addModification(
+ accessControlledIdFromAceNode(parent),
+ AccessControlObserver.POLICY_MODIFIED);
+ } /* some other property below an access controlled node
+ changed -> not interested. (NOTE: rep:ACL doesn't
+ define any properties. */
}
+
+ private NodeId accessControlledIdFromAclNode(Node aclNode)
+ throws RepositoryException {
+ return ((NodeImpl) aclNode.getParent()).getNodeId();
+ }
+
+ private NodeId accessControlledIdFromAceNode(Node aceNode)
+ throws RepositoryException {
+ return accessControlledIdFromAclNode(aceNode.getParent());
+ }
+
+ private void addModification(NodeId accessControllNodeId, int modType) {
+ if (modMap.containsKey(accessControllNodeId)) {
+ // update modMap
+ modType |= modMap.get(accessControllNodeId);
+ }
+ modMap.put(accessControllNodeId, modType);
+ }
+
}
-}
\ No newline at end of file
+
+}
Modified: jackrabbit/branches/2.2/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.2/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java?rev=1089453&r1=1089452&r2=1089453&view=diff
==============================================================================
--- jackrabbit/branches/2.2/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java (original)
+++ jackrabbit/branches/2.2/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java Wed Apr 6 13:48:24 2011
@@ -51,6 +51,14 @@ public class DefaultISMLocking implement
};
/**
+ * Flag for determining whether this locking strategy should give
+ * preference to writers or not. If writers are preferred (which
+ * is the default setting), then all readers will get blocked whenever
+ * there's a writer waiting for the lock.
+ */
+ private boolean writerPreference = true;
+
+ /**
* Number of writer threads waiting. While greater than zero, no new
* (unrelated) readers are allowed to proceed.
*/
@@ -79,6 +87,24 @@ public class DefaultISMLocking implement
private int readerCount = 0;
/**
+ * Returns the writer preference status of this locking strategy.
+ *
+ * @return writer preference
+ */
+ public boolean isWriterPreference() {
+ return writerPreference;
+ }
+
+ /**
+ * Sets the writer preference status of this locking strategy.
+ *
+ * @param preference writer preference
+ */
+ public void setWriterPreference(boolean preference) {
+ this.writerPreference = preference;
+ }
+
+ /**
* Increments the reader count and returns the acquired read lock once
* there are no more writers or the current writer shares the thread id
* with this reader.
@@ -88,7 +114,7 @@ public class DefaultISMLocking implement
Object currentId = getCurrentThreadId();
while (writerId != null
? (writerCount > 0 && !isSameThreadId(writerId, currentId))
- : writersWaiting > 0) {
+ : (writerPreference && writersWaiting > 0)) {
wait();
}