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 2012/01/27 20:07:39 UTC

svn commit: r1236837 - in /jackrabbit/branches/2.4: ./ jackrabbit-jcr-server/ jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/ jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/jcr/ jackrabbit-jcr-server/src/main/java/or...

Author: jukka
Date: Fri Jan 27 19:07:38 2012
New Revision: 1236837

URL: http://svn.apache.org/viewvc?rev=1236837&view=rev
Log:
2.4: Merged revisions 1236819, 1236820 and 1236821 (JCR-3222)

Added:
    jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/package-info.java
      - copied unchanged from r1236819, jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/package-info.java
Modified:
    jackrabbit/branches/2.4/   (props changed)
    jackrabbit/branches/2.4/jackrabbit-jcr-server/pom.xml
    jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/SessionProviderImpl.java
    jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/jcr/JCRWebdavServer.java
    jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/DavexServletService.java
    jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionImpl.java

Propchange: jackrabbit/branches/2.4/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri Jan 27 19:07:38 2012
@@ -1,3 +1,3 @@
 /jackrabbit/branches/JCR-2272:1173165-1176545
 /jackrabbit/sandbox/JCR-2415-lucene-3.0:1060860-1064038
-/jackrabbit/trunk:1221447,1221579,1221593,1221789,1221818,1225179,1225191,1225196,1225207,1225525,1225528,1226452,1226472,1226515,1226750,1226863,1227171,1227240,1227590,1227593,1227615,1228058,1228149,1228155,1228160,1230507,1230681,1230688,1231204,1232035,1232100,1232404,1232831,1232920,1232922,1233069,1233344,1233446,1233468,1233471,1234807,1235192,1235375,1235423,1236775
+/jackrabbit/trunk:1221447,1221579,1221593,1221789,1221818,1225179,1225191,1225196,1225207,1225525,1225528,1226452,1226472,1226515,1226750,1226863,1227171,1227240,1227590,1227593,1227615,1228058,1228149,1228155,1228160,1230507,1230681,1230688,1231204,1232035,1232100,1232404,1232831,1232920,1232922,1233069,1233344,1233446,1233468,1233471,1234807,1235192,1235375,1235423,1236775,1236819-1236821

Modified: jackrabbit/branches/2.4/jackrabbit-jcr-server/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.4/jackrabbit-jcr-server/pom.xml?rev=1236837&r1=1236836&r2=1236837&view=diff
==============================================================================
--- jackrabbit/branches/2.4/jackrabbit-jcr-server/pom.xml (original)
+++ jackrabbit/branches/2.4/jackrabbit-jcr-server/pom.xml Fri Jan 27 19:07:38 2012
@@ -71,13 +71,8 @@
         <configuration>
           <instructions>
             <Export-Package>
-              !*
+              org.apache.jackrabbit.server
             </Export-Package>
-            <Private-Package>
-              org.apache.jackrabbit.server.*,
-              org.apache.jackrabbit.webdav.jcr.*,
-              org.apache.jackrabbit.webdav.simple
-            </Private-Package>
           </instructions>
         </configuration>
       </plugin>
@@ -208,7 +203,12 @@
       <version>1.6.0</version>
       <scope>provided</scope>
     </dependency>
-    
+    <dependency>
+      <groupId>biz.aQute</groupId>
+      <artifactId>bndlib</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>

Modified: jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/SessionProviderImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/SessionProviderImpl.java?rev=1236837&r1=1236836&r2=1236837&view=diff
==============================================================================
--- jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/SessionProviderImpl.java (original)
+++ jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/SessionProviderImpl.java Fri Jan 27 19:07:38 2012
@@ -16,9 +16,9 @@
  */
 package org.apache.jackrabbit.server;
 
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Locale;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 
 import javax.jcr.Credentials;
 import javax.jcr.LoginException;
@@ -28,24 +28,31 @@ import javax.jcr.Session;
 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;
-
 /**
- * This Class implements a default session provider uses a credentials provider.
+ * This class implements a default session provider based on a given
+ * {@link CredentialsProvider credentials provider}. Additionally,
+ * since Jackrabbit 2.4, if another session provider is available as
+ * the "org.apache.jackrabbit.server.SessionProvider" request attribute,
+ * then that provider is asked first for a session before the default
+ * credential-based login mechanism is used.
  */
 public class SessionProviderImpl implements SessionProvider {
 
-    public static final String ATTRIBUTE_SESSION_ID = SessionProviderImpl.class + "#sessionid()";
-    
     /**
      * the credentials provider
      */
     private CredentialsProvider cp;
 
     /**
+     * Map of sessions acquired from custom session providers looked up
+     * from request attributes. We need to keep track of such providers
+     * so we can route the {@link #releaseSession(Session)} call to the
+     * correct provider.
+     */
+    private final Map<Session, SessionProvider> externalSessions =
+            Collections.synchronizedMap(new HashMap<Session, SessionProvider>());
+
+    /**
      * Creates a new SessionProvider
      * 
      * @param cp
@@ -60,25 +67,28 @@ public class SessionProviderImpl impleme
     public Session getSession(HttpServletRequest request,
             Repository repository, String workspace) throws LoginException,
             RepositoryException, ServletException {
-        Credentials creds = cp.getCredentials(request);
-        Session s;
-        if (creds == null) {
-            s = repository.login(workspace);
-        } else {
-            s = repository.login(creds, workspace);
+        Session s = null;
+
+        // JCR-3222: Check if a custom session provider is available as a
+        // request attribute. If one is available, ask it first for a session.
+        Object object = request.getAttribute(SessionProvider.class.getName());
+        if (object instanceof SessionProvider) {
+            SessionProvider provider = (SessionProvider) object;
+            s = provider.getSession(request, repository, workspace);
+            if (s != null) {
+                externalSessions.put(s, provider);
+            }
         }
 
-        // 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);
+        if (s == null) {
+            Credentials creds = cp.getCredentials(request);
+            if (creds == null) {
+                s = repository.login(workspace);
+            } else {
+                s = repository.login(creds, workspace);
+            }
         }
+
         return s;
     }
 
@@ -86,49 +96,14 @@ public class SessionProviderImpl impleme
      * {@inheritDoc }
      */
     public void releaseSession(Session session) {
-        session.logout();
-    }
-
-    // find first link relation for JCR User Data
-    private String getJcrUserData(LinkHeaderFieldParser lhfp) {
-        String jcrUserData = null;
-        String target = lhfp
-                .getFirstTargetForRelation(JcrRemotingConstants.RELATION_USER_DATA);
-        if (target != null) {
-            jcrUserData = getJcrUserData(target);
+        // JCR-3222: If the session was acquired from a custom session
+        // provider, we need to ask that provider to release the session.
+        SessionProvider provider = externalSessions.remove(session);
+        if (provider != null) {
+            provider.releaseSession(session);
+        } else {
+            session.logout();
         }
-
-        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) {
-        try {
-            URI datauri = new URI(target);
-
-            String scheme = datauri.getScheme();
-
-            // Poor Man's data: URI parsing
-            if (scheme != null
-                    && "data".equals(scheme.toLowerCase(Locale.ENGLISH))) {
-
-                String sspart = datauri.getRawSchemeSpecificPart();
-
-                if (sspart.startsWith(",")) {
-                    return Text.unescape(sspart.substring(1));
-                }
-            }
-        } catch (URISyntaxException ex) {
-            // not a URI, skip
-        }
-
-        return null;
-    }
 }

Modified: jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/jcr/JCRWebdavServer.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/jcr/JCRWebdavServer.java?rev=1236837&r1=1236836&r2=1236837&view=diff
==============================================================================
--- jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/jcr/JCRWebdavServer.java (original)
+++ jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/jcr/JCRWebdavServer.java Fri Jan 27 19:07:38 2012
@@ -16,7 +16,10 @@
  */
 package org.apache.jackrabbit.server.jcr;
 
+import org.apache.jackrabbit.commons.webdav.JcrRemotingConstants;
 import org.apache.jackrabbit.server.SessionProvider;
+import org.apache.jackrabbit.spi.commons.SessionExtensions;
+import org.apache.jackrabbit.util.Text;
 import org.apache.jackrabbit.webdav.DavException;
 import org.apache.jackrabbit.webdav.DavMethods;
 import org.apache.jackrabbit.webdav.DavSession;
@@ -25,6 +28,7 @@ import org.apache.jackrabbit.webdav.Webd
 import org.apache.jackrabbit.webdav.header.IfHeader;
 import org.apache.jackrabbit.webdav.jcr.JcrDavException;
 import org.apache.jackrabbit.webdav.jcr.JcrDavSession;
+import org.apache.jackrabbit.webdav.util.LinkHeaderFieldParser;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,8 +36,12 @@ import javax.jcr.LoginException;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletResponse;
+
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
@@ -325,7 +333,17 @@ public class JCRWebdavServer implements 
                 if (DavMethods.DAV_MKWORKSPACE != DavMethods.getMethodCode(request.getMethod())) {
                     workspaceName = request.getRequestLocator().getWorkspaceName();
                 }
-                return sessionProvider.getSession(request, repository, workspaceName);
+
+                Session session = sessionProvider.getSession(
+                        request, repository, workspaceName);
+
+                // extract information from Link header fields
+                LinkHeaderFieldParser lhfp =
+                        new LinkHeaderFieldParser(request.getHeaders("Link"));
+                setJcrUserData(session, lhfp);
+                setSessionIdentifier(session, lhfp);
+
+                return session;
             } catch (LoginException e) {
                 // LoginException results in UNAUTHORIZED,
                 throw new JcrDavException(e);
@@ -337,6 +355,53 @@ public class JCRWebdavServer implements 
             }
         }
 
+        /**
+         * Find first link relation for JCR user data and set it as
+         * the user data of the observation manager of the given session.
+         */
+        private void setJcrUserData(
+                Session session, LinkHeaderFieldParser lhfp)
+                throws RepositoryException {
+            String data = null;
+
+            // extract User Data string from RFC 2397 "data" URI
+            // only supports the simple case of "data:,..." for now
+            String target = lhfp.getFirstTargetForRelation(
+                    JcrRemotingConstants.RELATION_USER_DATA);
+            if (target != null) {
+                try {
+                    URI uri = new URI(target);
+                    // Poor Man's data: URI parsing
+                    if ("data".equalsIgnoreCase(uri.getScheme())) {
+                        String sspart = uri.getRawSchemeSpecificPart();
+                        if (sspart.startsWith(",")) {
+                            data = Text.unescape(sspart.substring(1));
+                        }
+                    }
+                } catch (URISyntaxException ex) {
+                    // not a URI, skip
+                }
+            }
+
+            try {
+                session.getWorkspace().getObservationManager().setUserData(data);
+            } catch (UnsupportedRepositoryOperationException ignore) {
+            }
+        }
+
+        /**
+         * Find first link relation for remote session identifier and set
+         * it as an attribute of the given session.
+         */
+        private void setSessionIdentifier(
+                Session session, LinkHeaderFieldParser lhfp) {
+            if (session instanceof SessionExtensions) {
+                String name = JcrRemotingConstants.RELATION_REMOTE_SESSION_ID;
+                String id = lhfp.getFirstTargetForRelation(name);
+                ((SessionExtensions) session).setAttribute(name, id);
+            }
+        }
+
         private String getUserID(DavSession session) {
             try {
                 Session s = DavSessionImpl.getRepositorySession(session);

Modified: jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/DavexServletService.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/DavexServletService.java?rev=1236837&r1=1236836&r2=1236837&view=diff
==============================================================================
--- jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/DavexServletService.java (original)
+++ jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/DavexServletService.java Fri Jan 27 19:07:38 2012
@@ -18,17 +18,29 @@
  */
 package org.apache.jackrabbit.server.remoting.davex;
 
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Set;
 
+import javax.jcr.LoginException;
 import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
 import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
 
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Properties;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.ReferencePolicy;
 import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.server.SessionProvider;
 import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet;
 import org.apache.jackrabbit.webdav.util.CSRFUtil;
 
@@ -38,8 +50,15 @@ import org.apache.jackrabbit.webdav.util
     @Property(name = "service.description", value = "Apache Jackrabbit JcrRemoting Servlet"),
     @Property(name = JcrRemotingServlet.INIT_PARAM_AUTHENTICATE_HEADER, value = AbstractWebdavServlet.DEFAULT_AUTHENTICATE_HEADER),
     @Property(name = JcrRemotingServlet.INIT_PARAM_CSRF_PROTECTION, value = CSRFUtil.DISABLED),
-    @Property(name = JcrRemotingServlet.INIT_PARAM_MISSING_AUTH_MAPPING, value = "") })
-public class DavexServletService extends JcrRemotingServlet {
+    @Property(name = JcrRemotingServlet.INIT_PARAM_MISSING_AUTH_MAPPING, value = ""),
+    @Property(name = "contextId", value = "") })
+@Reference(
+        name = "providers", referenceInterface = SessionProvider.class,
+        policy = ReferencePolicy.DYNAMIC,
+        cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
+        bind = "addSessionProvider", unbind = "removeSessionProvider")
+public class DavexServletService extends JcrRemotingServlet
+        implements SessionProvider {
 
     /** Serial version UID */
     private static final long serialVersionUID = -901601294536148635L;
@@ -54,6 +73,22 @@ public class DavexServletService extends
 
     private String alias;
 
+    /**
+     * Currently available custom session providers. They're used
+     * first before the default provider gets consulted. The associated
+     * set of sessions is used to forcibly release all sessions acquired
+     * from a provider when that provider is being removed.
+     */
+    private final Map<SessionProvider, Set<Session>> providers =
+            new LinkedHashMap<SessionProvider, Set<Session>>();
+
+    /**
+     * Currently active sessions. Used to link a session to the correct
+     * provider in the {@link #releaseSession(Session)} method.
+     */
+    private final Map<Session, SessionProvider> sessions =
+            new HashMap<Session, SessionProvider>();
+
     @Override
     protected Repository getRepository() {
         return repository;
@@ -78,4 +113,78 @@ public class DavexServletService extends
         }
     }
 
+    @Override
+    protected SessionProvider getSessionProvider() {
+        return this;
+    }
+
+    /**
+     * Adds a custom session provider service.
+     *
+     * @param provider session provider
+     */
+    public synchronized void addSessionProvider(SessionProvider provider) {
+        providers.put(provider, new HashSet<Session>());
+    }
+
+    /**
+     * Removes a custom session provider service. All active sessions
+     * acquired from that provider are forcibly released.
+     *
+     * @param provider session provider
+     */
+    public synchronized void removeSessionProvider(SessionProvider provider) {
+        Set<Session> sessions = providers.remove(provider);
+        if (sessions != null) {
+            for (Session session : sessions) {
+                releaseSession(session);
+            }
+        }
+    }
+
+    //-----------------------------------------------------< SessionProvider >
+
+    /**
+     * Asks each available session provider in order for a session and
+     * returns the first session given. The default provider is used
+     * if no custom provider service is available or can provide a requested
+     * session.
+     */
+    public synchronized Session getSession(
+            HttpServletRequest request, Repository repository, String workspace)
+            throws LoginException, ServletException, RepositoryException {
+        SessionProvider provider = null;
+        Session session = null;
+
+        for (Map.Entry<SessionProvider, Set<Session>> entry : providers.entrySet()) {
+            provider = entry.getKey();
+            session = provider.getSession(request, repository, workspace);
+            if (session != null) {
+                entry.getValue().add(session);
+                break;
+            }
+        }
+
+        if (session == null) {
+            provider = super.getSessionProvider();
+            session = provider.getSession(request, repository, workspace);
+        }
+
+        if (session != null) {
+            sessions.put(session, provider);
+        }
+
+        return session;
+    }
+
+    /**
+     * Releases the given session using the provider from which it was acquired.
+     */
+    public synchronized void releaseSession(Session session) {
+        SessionProvider provider = sessions.remove(session);
+        if (provider != null) {
+            provider.releaseSession(session);
+        }
+    }
+
 }

Modified: jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionImpl.java?rev=1236837&r1=1236836&r2=1236837&view=diff
==============================================================================
--- jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionImpl.java (original)
+++ jackrabbit/branches/2.4/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionImpl.java Fri Jan 27 19:07:38 2012
@@ -17,7 +17,7 @@
 package org.apache.jackrabbit.webdav.jcr.observation;
 
 import org.apache.jackrabbit.commons.webdav.EventUtil;
-import org.apache.jackrabbit.server.SessionProviderImpl;
+import org.apache.jackrabbit.commons.webdav.JcrRemotingConstants;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.commons.AdditionalEventInfo;
 import org.apache.jackrabbit.spi.commons.SessionExtensions;
@@ -462,17 +462,18 @@ public class SubscriptionImpl implements
                 if (!localFlagSet) {
                     // obtain remote session identifier
                     localFlagSet = true;
-                    String forSessionId = (String) session
-                            .getAttribute(SessionProviderImpl.ATTRIBUTE_SESSION_ID);
+                    String name = JcrRemotingConstants.RELATION_REMOTE_SESSION_ID;
+                    Object forSessionId = session.getAttribute(name);
                     // calculate "local" flags
                     if (forSessionId != null
                             && event instanceof AdditionalEventInfo) {
+                        AdditionalEventInfo aei = (AdditionalEventInfo) event;
                         try {
-                            String eventforSessionId = (String) ((AdditionalEventInfo) event)
-                                    .getSessionAttribute(SessionProviderImpl.ATTRIBUTE_SESSION_ID);
-                            boolean isLocal = forSessionId
-                                    .equals(eventforSessionId);
-                            DomUtil.setAttribute(bundle, XML_EVENT_LOCAL, null, Boolean.toString(isLocal));
+                            boolean isLocal = forSessionId.equals(
+                                    aei.getSessionAttribute(name));
+                            DomUtil.setAttribute(
+                                    bundle, XML_EVENT_LOCAL, null,
+                                    Boolean.toString(isLocal));
                         } catch (UnsupportedRepositoryOperationException ex) {
                             // optional feature
                         }