Return-Path: Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: (qmail 43565 invoked from network); 6 Apr 2011 14:08:15 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 6 Apr 2011 14:08:15 -0000 Received: (qmail 20133 invoked by uid 500); 6 Apr 2011 14:08:15 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 20042 invoked by uid 500); 6 Apr 2011 14:08:15 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 20035 invoked by uid 99); 6 Apr 2011 14:08:15 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 06 Apr 2011 14:08:15 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 06 Apr 2011 14:08:13 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 05E6723888CD; Wed, 6 Apr 2011 14:07:53 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1089463 - in /jackrabbit/branches/2.1: ./ 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... Date: Wed, 06 Apr 2011 14:07:52 -0000 To: commits@jackrabbit.apache.org From: jukka@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20110406140753.05E6723888CD@eris.apache.org> Author: jukka Date: Wed Apr 6 14:07:52 2011 New Revision: 1089463 URL: http://svn.apache.org/viewvc?rev=1089463&view=rev Log: 2.1: Merged revision 1089453 (JCR-2890) Modified: jackrabbit/branches/2.1/ (props changed) jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java Propchange: jackrabbit/branches/2.1/ ------------------------------------------------------------------------------ --- svn:mergeinfo (original) +++ svn:mergeinfo Wed Apr 6 14:07:52 2011 @@ -1,6 +1,6 @@ /jackrabbit/branches/1.5:794012,794100,794102 -/jackrabbit/branches/2.2:1065610,1067910,1071647,1071665,1071668 +/jackrabbit/branches/2.2:1065610,1067910,1071647,1071665,1071668,1089453 /jackrabbit/sandbox/JCR-1456:774917-886178 /jackrabbit/sandbox/JCR-2170:812417-816332 /jackrabbit/sandbox/tripod-JCR-2209:795441-795863 -/jackrabbit/trunk:931121,931479,931483-931484,931504,931609,931613,931838,931919,932318-932319,933144,933197,933203,933213,933216,933554,933646,933694,934405,934412,934849,935557,936668,938099,945528,950440,950680,955222,955229,955307,955852,961487,961626,964362,965539,986682,986686,986715,991144,995411-995412,996810,999298-999299,999965,1000947,1001707,1002065-1002066,1002084,1002101-1002102,1002168,1002170,1002589,1002608,1002657,1002729,1003423,1003470,1003542,1003773,1004182,1004184,1004223-1004224,1004652,1005057,1005112,1036117,1036336-1036337,1038201,1039064,1039423,1040090,1065599,1069831,1071562,1071573 +/jackrabbit/trunk:931121,931479,931483-931484,931504,931609,931613,931838,931919,932318-932319,933144,933197,933203,933213,933216,933554,933646,933694,934405,934412,934849,935557,936668,938099,945528,950440,950680,955222,955229,955307,955852,961487,961626,964362,965539,986682,986686,986715,991144,995411-995412,996810,999298-999299,999965,1000947,1001707,1002065-1002066,1002084,1002101-1002102,1002168,1002170,1002589,1002608,1002657,1002729,1003423,1003470,1003542,1003773,1004182,1004184,1004223-1004224,1004652,1005057,1005112,1036117,1036336-1036337,1038201,1039064,1039423,1040090,1065599,1069831,1071562,1071573,1087304,1089436 Modified: jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java?rev=1089463&r1=1089462&r2=1089463&view=diff ============================================================================== --- jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java (original) +++ jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java Wed Apr 6 14:07:52 2011 @@ -107,6 +107,23 @@ class SystemSession extends SessionImpl return new SystemAccessManager(); } + /** + * Creates and returns a new system session for the + * given workspace. + * + * @param workspaceName workspace name, + * or null for the default workspace + */ + @Override + public SessionImpl createSession(String workspaceName) + throws RepositoryException { + if (workspaceName == null) { + workspaceName = rep.getConfig().getDefaultWorkspaceName(); + } + + return create(rep, rep.getWorkspaceInfo(workspaceName).getConfig()); + } + //--------------------------------------------------------< inner classes > /** * An access manager that grants access to everything. Modified: jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java?rev=1089463&r1=1089462&r2=1089463&view=diff ============================================================================== --- jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java (original) +++ jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java Wed Apr 6 14:07:52 2011 @@ -22,12 +22,14 @@ import org.apache.jackrabbit.core.id.Nod import org.apache.jackrabbit.core.security.authorization.AccessControlConstants; import org.apache.jackrabbit.core.security.authorization.AccessControlModifications; import org.apache.jackrabbit.core.security.authorization.AccessControlObserver; +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; @@ -56,8 +58,6 @@ public class EntryCollector extends Acce protected final NodeId rootID; private final ACLEditor systemEditor; - - private final String repPolicyName; /** * @@ -70,7 +70,6 @@ public class EntryCollector extends Acce this.systemSession = systemSession; this.systemEditor = systemEditor; this.rootID = rootID; - repPolicyName = systemSession.getJCRName(N_POLICY); ObservationManager observationMgr = systemSession.getWorkspace().getObservationManager(); /* @@ -193,102 +192,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 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 modMap = new HashMap(); - - // 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 mods = + sieve.getModifications(); + if (!mods.getNodeIdentifiers().isEmpty()) { + notifyListeners(mods); + } + } finally { + session.logout(); + } + } catch (RepositoryException e) { + log.error("Failed to process access control modifications", e); + } + } + + /** + * 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 { - switch (ev.getType()) { + /** 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 modMap = + new HashMap(); + + 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(modMap)); + /** + * Returns the access control modifications collected from + * related observation events. + * + * @return access control modifications + */ + public AccessControlModifications getModifications() { + return new AccessControlModifications(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.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java?rev=1089463&r1=1089462&r2=1089463&view=diff ============================================================================== --- jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java (original) +++ jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java Wed Apr 6 14:07:52 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(); }