jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From resc...@apache.org
Subject svn commit: r1203173 - in /jackrabbit/trunk: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/ jackrabbit-core/src/main/resources-filtered/org/apache/jackrabbit/core/ jackrab...
Date Thu, 17 Nov 2011 12:47:59 GMT
Author: reschke
Date: Thu Nov 17 12:47:58 2011
New Revision: 1203173

URL: http://svn.apache.org/viewvc?rev=1203173&view=rev
Log:
JCR-2542: spi2dav: EventFilters not respected

- spi.commons extension interface for Session extension
- noLocal flag support
- client sends session identifier (in Link header field) on write operations so that POLL
can compute the flag
- SUBSCRIBE returns flags indicating extension features 

Added:
    jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/SessionExtensions.java
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/resources-filtered/org/apache/jackrabbit/core/repository.properties
    jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/webdav/JcrRemotingConstants.java
    jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/SessionProviderImpl.java
    jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionImpl.java
    jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionManagerImpl.java
    jackrabbit/trunk/jackrabbit-jcr2dav/pom.xml
    jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/AdditionalEventInfo.java
    jackrabbit/trunk/jackrabbit-spi2dav/pom.xml
    jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/EventImpl.java
    jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java
    jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/SessionInfoImpl.java
    jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/ObservationConstants.java
    jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/Subscription.java
    jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/SubscriptionDiscovery.java
    jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/util/LinkHeaderFieldParser.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
Thu Nov 17 12:47:58 2011
@@ -94,6 +94,7 @@ import org.apache.jackrabbit.core.xml.Im
 import org.apache.jackrabbit.core.xml.SessionImporter;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.commons.SessionExtensions;
 import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
 import org.apache.jackrabbit.spi.commons.conversion.IdentifierResolver;
 import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException;
@@ -111,7 +112,7 @@ import org.xml.sax.ContentHandler;
  * A <code>SessionImpl</code> ...
  */
 public class SessionImpl extends AbstractSession
-        implements JackrabbitSession, NamespaceResolver, NamePathResolver, IdentifierResolver
{
+        implements JackrabbitSession, SessionExtensions, NamespaceResolver, NamePathResolver,
IdentifierResolver {
 
     /**
      * Name of the session attribute that controls whether the
@@ -510,7 +511,7 @@ public class SessionImpl extends Abstrac
      * @param value attribute value
      * @since Apache Jackrabbit 1.6
      */
-    protected void setAttribute(String name, Object value) {
+    public void setAttribute(String name, Object value) {
         if (value != null) {
             attributes.put(name, value);
         } else {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java
Thu Nov 17 12:47:58 2011
@@ -223,6 +223,8 @@ public final class EventImpl implements 
         return eventState.isExternal();
     }
 
+    //---------------------------------------------------------------< AdditionalEventInfo
>
+
     /**
      * @return the primary node type of the node associated with the event
      * @see AdditionalEventInfo#getPrimaryNodeTypeName()
@@ -230,7 +232,7 @@ public final class EventImpl implements 
     public Name getPrimaryNodeTypeName() {
         return eventState.getNodeType();
     }
-    
+
     /**
      * @return the mixin node types of the node associated with the event
      * @see AdditionalEventInfo#getMixinTypeNames()
@@ -240,6 +242,13 @@ public final class EventImpl implements 
     }
 
     /**
+     * @return the specified session attribute
+     */
+    public Object getSessionAttribute(String name) {
+        return eventState.getSession().getAttribute(name);
+    }
+
+    /**
      * Returns a String representation of this <code>Event</code>.
      *
      * @return a String representation of this <code>Event</code>.

Modified: jackrabbit/trunk/jackrabbit-core/src/main/resources-filtered/org/apache/jackrabbit/core/repository.properties
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/resources-filtered/org/apache/jackrabbit/core/repository.properties?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/resources-filtered/org/apache/jackrabbit/core/repository.properties
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/resources-filtered/org/apache/jackrabbit/core/repository.properties
Thu Nov 17 12:47:58 2011
@@ -35,3 +35,6 @@ jcr.repository.name = Jackrabbit
 
 # The descriptor for the version of this repository implementation.
 jcr.repository.version = ${pom.version}
+
+# The repository supports the AdditionalEventInfo extension
+org.apache.jackrabbit.spi.commons.AdditionalEventInfo = true

Modified: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/webdav/JcrRemotingConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/webdav/JcrRemotingConstants.java?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/webdav/JcrRemotingConstants.java
(original)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/webdav/JcrRemotingConstants.java
Thu Nov 17 12:47:58 2011
@@ -154,7 +154,7 @@ public interface JcrRemotingConstants {
     /**
      * RFC 5988 relation type for user data
      * <p>
-     * We transport JCR User Data in a Link header field with this relation name
+     * Used to transport JCR User Data inside an HTTP request.
      * <p>
      * Example:
      * 
@@ -163,4 +163,17 @@ public interface JcrRemotingConstants {
      * </pre>
      */
     public static final String RELATION_USER_DATA = NS_URI + "/user-data";
+
+    /**
+     * RFC 5988 relation type for remote session identification
+     * <p>
+     * Used to transport an identifier for the remote session.
+     * <p>
+     * Example:
+     * 
+     * <pre>
+     * Link: <urn:uuid:96d3c6fe-1073-11e1-a3c0-00059a3c7a00>, rel="<i>RELATION_REMOTE_SESSION_ID</i>"
+     * </pre>
+     */
+    public static final String RELATION_REMOTE_SESSION_ID = NS_URI + "/session-id";
 }
\ No newline at end of file

Modified: jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/SessionProviderImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/SessionProviderImpl.java?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/SessionProviderImpl.java
(original)
+++ jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/SessionProviderImpl.java
Thu Nov 17 12:47:58 2011
@@ -18,7 +18,6 @@ package org.apache.jackrabbit.server;
 
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.util.Enumeration;
 import java.util.Locale;
 
 import javax.jcr.Credentials;
@@ -30,6 +29,7 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 
 import org.apache.jackrabbit.commons.webdav.JcrRemotingConstants;
+import org.apache.jackrabbit.spi.commons.SessionExtensions;
 import org.apache.jackrabbit.util.Text;
 import org.apache.jackrabbit.webdav.util.LinkHeaderFieldParser;
 
@@ -38,6 +38,8 @@ import org.apache.jackrabbit.webdav.util
  */
 public class SessionProviderImpl implements SessionProvider {
 
+    public static final String ATTRIBUTE_SESSION_ID = SessionProviderImpl.class + "#sessionid()";
+    
     /**
      * the credentials provider
      */
@@ -65,8 +67,18 @@ public class SessionProviderImpl impleme
         } else {
             s = repository.login(creds, workspace);
         }
-        String userData = getJcrUserData(request);
+
+        // extract information from Link header fields
+        LinkHeaderFieldParser lhfp = new LinkHeaderFieldParser(
+                request.getHeaders("Link"));
+        String userData = getJcrUserData(lhfp);
         s.getWorkspace().getObservationManager().setUserData(userData);
+
+        String sessionId = getSessionIdentifier(lhfp);
+        if (s instanceof SessionExtensions) {
+            SessionExtensions xs = (SessionExtensions) s;
+            xs.setAttribute(ATTRIBUTE_SESSION_ID, sessionId);
+        }
         return s;
     }
 
@@ -78,20 +90,23 @@ public class SessionProviderImpl impleme
     }
 
     // find first link relation for JCR User Data
-    private String getJcrUserData(HttpServletRequest request) {
+    private String getJcrUserData(LinkHeaderFieldParser lhfp) {
         String jcrUserData = null;
-        Enumeration<?> fieldValues = request.getHeaders("link");
-        if (fieldValues.hasMoreElements()) {
-            LinkHeaderFieldParser lhfp = new LinkHeaderFieldParser(fieldValues);
-            String target = lhfp
-                    .getFirstTargetForRelation(JcrRemotingConstants.RELATION_USER_DATA);
-            if (target != null) {
-                jcrUserData = getJcrUserData(target);
-            }
+        String target = lhfp
+                .getFirstTargetForRelation(JcrRemotingConstants.RELATION_USER_DATA);
+        if (target != null) {
+            jcrUserData = getJcrUserData(target);
         }
+
         return jcrUserData;
     }
 
+    // find first link relation for remote session identifier
+    private String getSessionIdentifier(LinkHeaderFieldParser lhfp) {
+        return lhfp
+                .getFirstTargetForRelation(JcrRemotingConstants.RELATION_REMOTE_SESSION_ID);
+    }
+
     // extracts User Data string from RFC 2397 "data" URI
     // only supports the simple case of "data:,..." for now
     private String getJcrUserData(String target) {

Modified: jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionImpl.java?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionImpl.java
(original)
+++ jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionImpl.java
Thu Nov 17 12:47:58 2011
@@ -17,8 +17,11 @@
 package org.apache.jackrabbit.webdav.jcr.observation;
 
 import org.apache.jackrabbit.commons.webdav.EventUtil;
+import org.apache.jackrabbit.commons.webdav.JcrRemotingConstants;
+import org.apache.jackrabbit.server.SessionProviderImpl;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.commons.AdditionalEventInfo;
+import org.apache.jackrabbit.spi.commons.SessionExtensions;
 import org.apache.jackrabbit.webdav.DavException;
 import org.apache.jackrabbit.webdav.DavResourceLocator;
 import org.apache.jackrabbit.webdav.DavServletResponse;
@@ -42,8 +45,12 @@ import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
+import com.sun.org.apache.xalan.internal.xsltc.dom.ExtendedSAX;
+
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Value;
 import javax.jcr.observation.Event;
 import javax.jcr.observation.EventIterator;
 import javax.jcr.observation.EventListener;
@@ -73,6 +80,7 @@ public class SubscriptionImpl implements
     private final String subscriptionId = UUID.randomUUID().toString();
     private final List<EventBundle> eventBundles = new ArrayList<EventBundle>();
     private final ObservationManager obsMgr;
+    private final Session session;
 
     /**
      * Create a new <code>Subscription</code> with the given {@link SubscriptionInfo}
@@ -87,9 +95,9 @@ public class SubscriptionImpl implements
             throws DavException {
         setInfo(info);
         locator = resource.getLocator();
-        Session s = JcrDavSession.getRepositorySession(resource.getSession());
+        session = JcrDavSession.getRepositorySession(resource.getSession());
         try {
-            obsMgr = s.getWorkspace().getObservationManager();
+            obsMgr = session.getWorkspace().getObservationManager();
         } catch (RepositoryException e) {
             throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, e);
         }
@@ -105,6 +113,15 @@ public class SubscriptionImpl implements
         return subscriptionId;
     }
 
+    public boolean eventsProvideNodeTypeInformation() {
+        String t = session.getRepository().getDescriptor("org.apache.jackrabbit.spi.commons.AdditionalEventInfo");
+        return t == null ? false : Boolean.parseBoolean(t);
+    }
+
+    public boolean eventsProvideNoLocalFlag() {
+        return session instanceof SessionExtensions;
+    }
+
     //----------------------------------------------------< XmlSerializable >---
     /**
      * Return the Xml representation of this <code>Subscription</code> as required
@@ -127,6 +144,12 @@ public class SubscriptionImpl implements
             Element id = DomUtil.addChildElement(subscr, XML_SUBSCRIPTIONID, NAMESPACE);
             id.appendChild(DomUtil.hrefToXml(getSubscriptionId(), document));
         }
+
+        DomUtil.addChildElement(subscr, XML_EVENTSWITHTYPES, NAMESPACE,
+                Boolean.toString(eventsProvideNodeTypeInformation()));
+        DomUtil.addChildElement(subscr, XML_EVENTSWITHLOCALFLAG, NAMESPACE,
+                Boolean.toString(eventsProvideNoLocalFlag()));
+
         return subscr;
     }
 
@@ -430,11 +453,37 @@ public class SubscriptionImpl implements
 
         public Element toXml(Document document) {
             Element bundle = DomUtil.createElement(document, XML_EVENTBUNDLE, NAMESPACE);
+            // TODO: this appears to be unused now
             if (transactionId != null) {
                 DomUtil.setAttribute(bundle, XML_EVENT_TRANSACTION_ID, NAMESPACE, transactionId);
             }
+
+            boolean localFlagSet = false;
+
             while (events.hasNext()) {
                 Event event = events.nextEvent();
+
+                if (!localFlagSet) {
+                    // obtain remote session identifier
+                    localFlagSet = true;
+                    String forSessionId = (String) session
+                            .getAttribute(SessionProviderImpl.ATTRIBUTE_SESSION_ID);
+                    // calculate "local" flags
+                    if (forSessionId != null
+                            && event instanceof AdditionalEventInfo) {
+                        try {
+                            String eventforSessionId = (String) ((AdditionalEventInfo) event)
+                                    .getSessionAttribute(SessionProviderImpl.ATTRIBUTE_SESSION_ID);
+                            boolean isLocal = forSessionId
+                                    .equals(eventforSessionId);
+                            DomUtil.setAttribute(bundle, XML_EVENT_LOCAL,
+                                    NAMESPACE, Boolean.toString(isLocal));
+                        } catch (UnsupportedRepositoryOperationException ex) {
+                            // optional feature
+                        }
+                    }
+                }
+
                 Element eventElem = DomUtil.addChildElement(bundle, XML_EVENT, NAMESPACE);
                 // href
                 String eHref = "";
@@ -452,12 +501,21 @@ public class SubscriptionImpl implements
                 // user id
                 DomUtil.addChildElement(eventElem, XML_EVENTUSERID, NAMESPACE, event.getUserID());
 
+                // try to compute nodetype information
                 if (event instanceof AdditionalEventInfo) {
-                    DomUtil.addChildElement(eventElem, "primarynodetype", NAMESPACE,
-                            ((AdditionalEventInfo)event).getPrimaryNodeTypeName().toString());
-                    for (Name mixin : ((AdditionalEventInfo)event).getMixinTypeNames()) {
-                        DomUtil.addChildElement(eventElem, "mixinnodetype", NAMESPACE,
-                                mixin.toString());
+                    try {
+                        DomUtil.addChildElement(eventElem,
+                                XML_EVENTPRIMARNODETYPE, NAMESPACE,
+                                ((AdditionalEventInfo) event)
+                                        .getPrimaryNodeTypeName().toString());
+                        for (Name mixin : ((AdditionalEventInfo) event)
+                                .getMixinTypeNames()) {
+                            DomUtil.addChildElement(eventElem,
+                                    XML_EVENTPRIMARNODETYPE, NAMESPACE,
+                                    mixin.toString());
+                        }
+                    } catch (UnsupportedRepositoryOperationException ex) {
+                        // optional
                     }
                 }
 

Modified: jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionManagerImpl.java?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionManagerImpl.java
(original)
+++ jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionManagerImpl.java
Thu Nov 17 12:47:58 2011
@@ -288,6 +288,14 @@ public class SubscriptionManagerImpl imp
         public Element toXml(Document document) {
             return delegatee.toXml(document);
         }
+
+        public boolean eventsProvideNodeTypeInformation() {
+            return delegatee.eventsProvideNodeTypeInformation();
+        }
+
+        public boolean eventsProvideNoLocalFlag() {
+            return delegatee.eventsProvideNoLocalFlag();
+        }
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-jcr2dav/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2dav/pom.xml?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2dav/pom.xml (original)
+++ jackrabbit/trunk/jackrabbit-jcr2dav/pom.xml Thu Nov 17 12:47:58 2011
@@ -80,8 +80,6 @@
                       org.apache.jackrabbit.test.api.observation.GetIdentifierTest#testNodeRemoved
                     
                       <!-- JCR-2541 : event journal -->
                       org.apache.jackrabbit.test.api.observation.EventJournalTest
-                      <!-- JCR-2542 : event filter -->
-                      org.apache.jackrabbit.test.api.observation.AddEventListenerTest#testNoLocalTrue
                       <!-- JCR-2533 : missing impl of checkQueryStatement -->     
                
                       org.apache.jackrabbit.test.api.query.CreateQueryTest#testUnknownQueryLanguage
                       <!-- JCR-2543 : query offset -->

Modified: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/AdditionalEventInfo.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/AdditionalEventInfo.java?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/AdditionalEventInfo.java
(original)
+++ jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/AdditionalEventInfo.java
Thu Nov 17 12:47:58 2011
@@ -18,6 +18,8 @@ package org.apache.jackrabbit.spi.common
 
 import java.util.Set;
 
+import javax.jcr.UnsupportedRepositoryOperationException;
+
 import org.apache.jackrabbit.spi.Event;
 import org.apache.jackrabbit.spi.Name;
 
@@ -29,10 +31,15 @@ public interface AdditionalEventInfo {
 	/**
 	 * @return the name of the primary node type of the node associated with the event
 	 */
-    public Name getPrimaryNodeTypeName();
-    
+    public Name getPrimaryNodeTypeName() throws UnsupportedRepositoryOperationException;
+
 	/**
 	 * @return the names of the mixin node types of the node associated with the event
 	 */
-    public Set<Name> getMixinTypeNames();
+    public Set<Name> getMixinTypeNames() throws UnsupportedRepositoryOperationException;
+
+    /**
+     * @return the specified Session attribute
+     */
+    public Object getSessionAttribute(String name) throws UnsupportedRepositoryOperationException;
 }

Added: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/SessionExtensions.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/SessionExtensions.java?rev=1203173&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/SessionExtensions.java
(added)
+++ jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/SessionExtensions.java
Thu Nov 17 12:47:58 2011
@@ -0,0 +1,32 @@
+/*
+ * 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.spi.commons;
+
+import javax.jcr.Session;
+
+/**
+ * Provides additional methods for {@link Session} access..
+ */
+public interface SessionExtensions {
+
+	/**
+	 * Sets the specified {@link Session} attribute.
+	 * @param name attribute name
+	 * @param value attribute value
+	 */
+	public void setAttribute(String name, Object value);
+}

Modified: jackrabbit/trunk/jackrabbit-spi2dav/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi2dav/pom.xml?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi2dav/pom.xml (original)
+++ jackrabbit/trunk/jackrabbit-spi2dav/pom.xml Thu Nov 17 12:47:58 2011
@@ -77,8 +77,6 @@
                   org.apache.jackrabbit.test.api.observation.GetIdentifierTest#testNodeRemoved
                   <!-- JCR-2541 : event journal -->
                   org.apache.jackrabbit.test.api.observation.EventJournalTest
-                  <!-- JCR-2542 : event filter -->
-                  org.apache.jackrabbit.test.api.observation.AddEventListenerTest#testNoLocalTrue
                   <!-- JCR-2533 : missing impl of checkQueryStatement -->
                   org.apache.jackrabbit.test.api.query.CreateQueryTest#testUnknownQueryLanguage
                   <!-- JCR-2543 : query offset -->

Modified: jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/EventImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/EventImpl.java?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/EventImpl.java
(original)
+++ jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/EventImpl.java
Thu Nov 17 12:47:58 2011
@@ -57,15 +57,22 @@ public class EventImpl
 
     private static final NameFactory N_FACTORY = NameFactoryImpl.getInstance();
 
-    public EventImpl(ItemId eventId, Path eventPath, NodeId parentId, int eventType,
-                     Element eventElement, NamePathResolver resolver, QValueFactory qvFactory)
throws NamespaceException, IllegalNameException {
+    public EventImpl(ItemId eventId, Path eventPath, NodeId parentId,
+            int eventType, Element eventElement, NamePathResolver resolver,
+            QValueFactory qvFactory) throws NamespaceException,
+            IllegalNameException {
         super(getSpiEventType(eventType), eventPath, eventId, parentId,
-                resolver.getQName(DomUtil.getChildTextTrim(eventElement, "primarynodetype",
NAMESPACE)),
-                getNames(DomUtil.getChildren(eventElement, "mixinnodetype", NAMESPACE), resolver),
-                DomUtil.getChildTextTrim(eventElement, XML_EVENTUSERID, NAMESPACE),
-                DomUtil.getChildTextTrim(eventElement, XML_EVENTUSERDATA, NAMESPACE),
-                Long.parseLong(DomUtil.getChildTextTrim(eventElement, XML_EVENTDATE, NAMESPACE)),
-                getEventInfo(DomUtil.getChildElement(eventElement, XML_EVENTINFO, NAMESPACE),
resolver, qvFactory));
+                resolver.getQName(DomUtil.getChildTextTrim(eventElement,
+                        XML_EVENTPRIMARNODETYPE, NAMESPACE)), getNames(
+                        DomUtil.getChildren(eventElement,
+                                XML_EVENTMIXINNODETYPE, NAMESPACE), resolver),
+                DomUtil.getChildTextTrim(eventElement, XML_EVENTUSERID,
+                        NAMESPACE), DomUtil.getChildTextTrim(eventElement,
+                        XML_EVENTUSERDATA, NAMESPACE), Long.parseLong(DomUtil
+                        .getChildTextTrim(eventElement, XML_EVENTDATE,
+                                NAMESPACE)), getEventInfo(
+                        DomUtil.getChildElement(eventElement, XML_EVENTINFO,
+                                NAMESPACE), resolver, qvFactory));
     }
 
     //--------------------------------------------------------------------------

Modified: jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java
(original)
+++ jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java
Thu Nov 17 12:47:58 2011
@@ -171,6 +171,7 @@ import org.apache.jackrabbit.webdav.obse
 import org.apache.jackrabbit.webdav.observation.EventDiscovery;
 import org.apache.jackrabbit.webdav.observation.EventType;
 import org.apache.jackrabbit.webdav.observation.ObservationConstants;
+import org.apache.jackrabbit.webdav.observation.SubscriptionDiscovery;
 import org.apache.jackrabbit.webdav.observation.SubscriptionInfo;
 import org.apache.jackrabbit.webdav.ordering.OrderingConstants;
 import org.apache.jackrabbit.webdav.property.DavProperty;
@@ -245,6 +246,10 @@ public class RepositoryServiceImpl imple
     private final Map<String, QValue[]> descriptors =
             new HashMap<String, QValue[]>();
 
+    /** Observation features. */
+    private boolean remoteServerProvidesNodeTypes = false;
+    private boolean remoteServerProvidesNoLocalFlag = false;
+
     /**
      * Same as {@link #RepositoryServiceImpl(String, IdFactory, NameFactory, PathFactory,
QValueFactory, int, int)}
      * using {@link ItemInfoCacheImpl#DEFAULT_CACHE_SIZE)} as size for the item
@@ -376,22 +381,52 @@ public class RepositoryServiceImpl imple
                 method.setRequestHeader(ifH.getHeaderName(), ifH.getHeaderValue());
             }
         }
+        
+        initMethod(method, sessionInfo);
+    }
+
+    // set of HTTP methods that will not change the remote state
+    private static final Set<String> readMethods;
+    static {
+        Set<String> tmp = new HashSet<String>();
+        tmp.add("GET");
+        tmp.add("HEAD");
+        tmp.add("PROPFIND");
+        tmp.add("POLL");
+        tmp.add("REPORT");
+        tmp.add("SEARCH");
+        readMethods = Collections.unmodifiableSet(tmp);
+    }
+
+    // set headers for user data and session identification
+    protected static void initMethod(HttpMethod method, SessionInfo sessionInfo) throws RepositoryException
{
+
+        boolean isReadAccess = readMethods.contains(method.getName());
+        boolean needsSessionId = !isReadAccess || "POLL".equals(method.getName());
+
+        if (sessionInfo instanceof SessionInfoImpl && needsSessionId) {
+            StringBuilder linkHeaderField = new StringBuilder();
+
+            String sessionIdentifier = ((SessionInfoImpl) sessionInfo)
+                    .getSessionIdentifier();
+            linkHeaderField.append("<" + sessionIdentifier + ">; rel=\""
+                    + JcrRemotingConstants.RELATION_REMOTE_SESSION_ID + "\"");
 
-        if (sessionInfo instanceof SessionInfoImpl) {
             String userdata = ((SessionInfoImpl) sessionInfo).getUserData();
-            if (userdata != null) {
+            if (userdata != null && ! isReadAccess) {
                 String escaped = Text.escape(userdata);
-                method.addRequestHeader("Link", "<data:," + escaped
-                        + ">; rel=\"" + JcrRemotingConstants.RELATION_USER_DATA
-                        + "\"");
+                linkHeaderField.append((", <data:," + escaped + ">; rel=\""
+                        + JcrRemotingConstants.RELATION_USER_DATA + "\""));
             }
+
+            method.addRequestHeader("Link", linkHeaderField.toString());
         }
     }
 
     private static void initMethod(DavMethod method, BatchImpl batchImpl, boolean addIfHeader)
throws RepositoryException {
         initMethod(method, batchImpl.sessionInfo,  addIfHeader);
 
-        // add batchId as separate header
+        // add batchId as separate header, TODO: could probably re-use session id Link relation
         CodedUrlHeader ch = new CodedUrlHeader(TransactionConstants.HEADER_TRANSACTIONID,
batchImpl.batchId);
         method.setRequestHeader(ch.getHeaderName(), ch.getHeaderValue());
     }
@@ -1254,7 +1289,7 @@ public class RepositoryServiceImpl imple
             } else if (ct.startsWith("text/xml")) {
                 // jcr:values property spooled
                 values = getValues(method.getResponseBodyAsStream(), resolver, propertyId);
-                type = (values.length > 0) ? values[0].getType() : loadType(uri, client,
propertyId, resolver);
+                type = (values.length > 0) ? values[0].getType() : loadType(uri, client,
propertyId, sessionInfo, resolver);
                 isMultiValued = true;
             } else {
                 throw new ItemNotFoundException("Unable to retrieve the property with id
" + saveGetIdString(propertyId, resolver));
@@ -1312,7 +1347,7 @@ public class RepositoryServiceImpl imple
         }
     }
 
-    private int loadType(String propertyURI, HttpClient client, PropertyId propertyId, NamePathResolver
resolver) throws IOException, DavException, RepositoryException {
+    private int loadType(String propertyURI, HttpClient client, PropertyId propertyId, SessionInfo
sessionInfo, NamePathResolver resolver) throws IOException, DavException, RepositoryException
{
         DavPropertyNameSet nameSet = new DavPropertyNameSet();
         nameSet.add(JcrRemotingConstants.JCR_TYPE_LN, ItemResourceConstants.NAMESPACE);
 
@@ -2001,11 +2036,19 @@ public class RepositoryServiceImpl imple
     public Subscription createSubscription(SessionInfo sessionInfo,
                                            EventFilter[] filters)
             throws UnsupportedRepositoryOperationException, RepositoryException {
-        checkEventFilterSupport(filters);
+
         checkSessionInfo(sessionInfo);
         String rootUri = uriResolver.getRootItemUri(sessionInfo.getWorkspaceName());
         String subscriptionId = subscribe(rootUri, S_INFO, null, sessionInfo, null);
         log.debug("Subscribed on server for session info " + sessionInfo);
+
+        try {
+            checkEventFilterSupport(filters);
+        }
+        catch (UnsupportedRepositoryOperationException ex) {
+            unsubscribe(rootUri, subscriptionId, sessionInfo);
+            throw (ex);
+        }
         return new EventSubscriptionImpl(subscriptionId, (SessionInfoImpl) sessionInfo);
     }
 
@@ -2021,13 +2064,19 @@ public class RepositoryServiceImpl imple
         checkEventFilterSupport(filters);
     }
 
-    private void checkEventFilterSupport(EventFilter[] filters) throws UnsupportedRepositoryOperationException
{
+    private void checkEventFilterSupport(EventFilter[] filters)
+            throws UnsupportedRepositoryOperationException {
         for (EventFilter ef : filters) {
             if (ef instanceof EventFilterImpl) {
-                EventFilterImpl efi = (EventFilterImpl)ef;
-                // TODO: add code that verifies that the remote server can send node type
information
-                if (efi.getNoLocal()) {
-                    throw new UnsupportedRepositoryOperationException("This SPI implementation
does not support filtering using the 'noLocal' flag (see issue JCR-2542)");
+                EventFilterImpl efi = (EventFilterImpl) ef;
+                if (efi.getNodeTypeNames() != null
+                        && !remoteServerProvidesNodeTypes) {
+                    throw new UnsupportedRepositoryOperationException(
+                            "Remote server does not provide node type information in events");
+                }
+                if (efi.getNoLocal() && !remoteServerProvidesNoLocalFlag) {
+                    throw new UnsupportedRepositoryOperationException(
+                            "Remote server does not provide local flag in events");
                 }
             }
         }
@@ -2051,6 +2100,7 @@ public class RepositoryServiceImpl imple
             } else {
                 method = new SubscribeMethod(uri, subscriptionInfo);
             }
+            initMethod(method, sessionInfo);
 
             if (batchId != null) {
                 // add batchId as separate header
@@ -2060,6 +2110,13 @@ public class RepositoryServiceImpl imple
 
             getClient(sessionInfo).executeMethod(method);
             method.checkSuccess();
+
+            org.apache.jackrabbit.webdav.observation.Subscription[] subs = method.getResponseAsSubscriptionDiscovery().getValue();
+            if (subs.length == 1) {
+                this.remoteServerProvidesNodeTypes = subs[0].eventsProvideNodeTypeInformation();
+                this.remoteServerProvidesNoLocalFlag = subs[0].eventsProvideNoLocalFlag();
+            }
+
             return method.getSubscriptionId();
         } catch (IOException e) {
             throw new RepositoryException(e);
@@ -2076,6 +2133,7 @@ public class RepositoryServiceImpl imple
         UnSubscribeMethod method = null;
         try {
             method = new UnSubscribeMethod(uri, subscriptionId);
+            initMethod(method, sessionInfo);
             getClient(sessionInfo).executeMethod(method);
             method.checkSuccess();
         } catch (IOException e) {
@@ -2121,12 +2179,12 @@ public class RepositoryServiceImpl imple
                 while (it.hasNext()) {
                     Element bundleElement = it.nextElement();
                     String value = DomUtil.getAttribute(bundleElement,
-                            ObservationConstants.XML_EVENT_TRANSACTION_ID,
+                            ObservationConstants.XML_EVENT_LOCAL,
                             ObservationConstants.NAMESPACE);
                     // check if it matches a batch id recently submitted
                     boolean isLocal = false;
                     if (value != null) {
-                        isLocal = value.equals(sessionInfo.getLastBatchId());
+                        isLocal = Boolean.parseBoolean(value);
                     }
                     bundles.add(new EventBundleImpl(
                             buildEventList(bundleElement, sessionInfo),

Modified: jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/SessionInfoImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/SessionInfoImpl.java?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/SessionInfoImpl.java
(original)
+++ jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/SessionInfoImpl.java
Thu Nov 17 12:47:58 2011
@@ -21,6 +21,7 @@ import org.apache.jackrabbit.spi.commons
 import java.util.HashSet;
 import java.util.Set;
 import java.util.Arrays;
+import java.util.UUID;
 
 /**
  * <code>SessionInfoImpl</code>...
@@ -29,7 +30,10 @@ public class SessionInfoImpl extends org
 
     private final CredentialsWrapper credentials;
     private final Set<String> sessionScopedTokens = new HashSet<String>();
-
+    
+    // a globally unique URI identifiying this session
+    private final String sessionIdentifier = "urn:uuid" + UUID.randomUUID();
+    
     private String lastBatchId;
     private NamePathResolver resolver;
 
@@ -54,6 +58,10 @@ public class SessionInfoImpl extends org
         return credentials;
     }
 
+    String getSessionIdentifier() {
+        return sessionIdentifier;
+    }
+
     /**
      * Returns the id of the most recently submitted batch or <code>null</code>
      * it no batch has been submitted yet.

Modified: jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/ObservationConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/ObservationConstants.java?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/ObservationConstants.java
(original)
+++ jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/ObservationConstants.java
Thu Nov 17 12:47:58 2011
@@ -61,18 +61,23 @@ public interface ObservationConstants {
     public static final String XML_NOLOCAL = "nolocal";
     public static final String XML_FILTER = "filter";
     public static final String XML_SUBSCRIPTIONID = "subscriptionid";
+    public static final String XML_EVENTSWITHTYPES = "eventswithnodetypes";
+    public static final String XML_EVENTSWITHLOCALFLAG = "eventswithlocalflag";
     public static final String XML_UUID = "uuid";
     public static final String XML_NODETYPE_NAME = "nodetype-name";
 
     public static final String XML_EVENTDISCOVERY = "eventdiscovery";
     public static final String XML_EVENTBUNDLE = "eventbundle";
     public static final String XML_EVENT_TRANSACTION_ID = "transactionid";
+    public static final String XML_EVENT_LOCAL = "local";
     public static final String XML_EVENT = "event";
     public static final String XML_EVENTUSERID = "eventuserid";
     public static final String XML_EVENTUSERDATA = "eventuserdata";
     public static final String XML_EVENTDATE = "eventdate";
     public static final String XML_EVENTIDENTIFIER = "eventidentifier";
     public static final String XML_EVENTINFO = "eventinfo";
+    public static final String XML_EVENTPRIMARNODETYPE = "eventprimarynodetype";
+    public static final String XML_EVENTMIXINNODETYPE = "eventmixinnodetype";
     
     //---< Property Names >-----------------------------------------------------
     /**

Modified: jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/Subscription.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/Subscription.java?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/Subscription.java
(original)
+++ jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/Subscription.java
Thu Nov 17 12:47:58 2011
@@ -36,4 +36,14 @@ public interface Subscription extends Xm
      * @return subscriptionId
      */
     public String getSubscriptionId();
+
+    /**
+     * @return whether events will be returned with node type information
+     */
+    public boolean eventsProvideNodeTypeInformation();
+
+    /**
+     * @return whether events will be returned with the "noLocal" flag
+     */
+    public boolean eventsProvideNoLocalFlag();
 }
\ No newline at end of file

Modified: jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/SubscriptionDiscovery.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/SubscriptionDiscovery.java?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/SubscriptionDiscovery.java
(original)
+++ jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/SubscriptionDiscovery.java
Thu Nov 17 12:47:58 2011
@@ -113,6 +113,17 @@ public class SubscriptionDiscovery exten
                     }
                     return null;
                 }
+
+                public boolean eventsProvideNodeTypeInformation() {
+                    String t = DomUtil.getChildText(sb, ObservationConstants.XML_EVENTSWITHTYPES,
ObservationConstants.NAMESPACE);
+                    return t == null ? false : Boolean.parseBoolean(t);
+                }
+
+                public boolean eventsProvideNoLocalFlag() {
+                    String t = DomUtil.getChildText(sb, ObservationConstants.XML_EVENTSWITHLOCALFLAG,
ObservationConstants.NAMESPACE);
+                    return t == null ? false : Boolean.parseBoolean(t);
+                }
+
                 /**
                  * @see XmlSerializable#toXml(Document)
                  */

Modified: jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/util/LinkHeaderFieldParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/util/LinkHeaderFieldParser.java?rev=1203173&r1=1203172&r2=1203173&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/util/LinkHeaderFieldParser.java
(original)
+++ jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/util/LinkHeaderFieldParser.java
Thu Nov 17 12:47:58 2011
@@ -57,13 +57,18 @@ public class LinkHeaderFieldParser {
 
     public LinkHeaderFieldParser(Enumeration<?> en) {
 
-        List<LinkRelation> tmp = new ArrayList<LinkRelation>();
+        if (en.hasMoreElements()) {
+            List<LinkRelation> tmp = new ArrayList<LinkRelation>();
 
-        while (en.hasMoreElements()) {
-            addFields(tmp, en.nextElement().toString());
-        }
+            while (en.hasMoreElements()) {
+                addFields(tmp, en.nextElement().toString());
+            }
 
-        relations = Collections.unmodifiableList(tmp);
+            relations = Collections.unmodifiableList(tmp);
+        } else {
+            // optimize case of no Link headers
+            relations = Collections.emptyList();
+        }
     }
 
     public String getFirstTargetForRelation(String relationType) {



Mime
View raw message