Work on JCR remoting
authorMathieu Baudier <mbaudier@argeo.org>
Tue, 22 Feb 2011 22:34:33 +0000 (22:34 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Tue, 22 Feb 2011 22:34:33 +0000 (22:34 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@4166 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

19 files changed:
eclipse/plugins/org.argeo.eclipse.ui.jcr/src/main/java/org/argeo/eclipse/ui/jcr/views/GenericJcrBrowser.java
server/modules/org.argeo.server.jackrabbit.webapp.war/.project [new file with mode: 0644]
server/modules/org.argeo.server.jackrabbit.webapp.war/.settings/org.eclipse.pde.core.prefs [new file with mode: 0644]
server/modules/org.argeo.server.jackrabbit.webapp.war/META-INF/MANIFEST.MF [new file with mode: 0644]
server/modules/org.argeo.server.jackrabbit.webapp.war/WEB-INF/applicationContext.xml [new file with mode: 0644]
server/modules/org.argeo.server.jackrabbit.webapp.war/WEB-INF/osgi.xml [new file with mode: 0644]
server/modules/org.argeo.server.jackrabbit.webapp.war/WEB-INF/remoting-servlet.xml [new file with mode: 0644]
server/modules/org.argeo.server.jackrabbit.webapp.war/WEB-INF/security.xml [new file with mode: 0644]
server/modules/org.argeo.server.jackrabbit.webapp.war/WEB-INF/web.xml [new file with mode: 0644]
server/modules/org.argeo.server.jackrabbit.webapp.war/build.properties [new file with mode: 0644]
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jackrabbit/JackrabbitContainer.java
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jackrabbit/webdav/CachingSessionProvider.java [new file with mode: 0644]
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jackrabbit/webdav/ExtendedDispatcherServlet.java
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jackrabbit/webdav/JcrRemotingServlet.java [new file with mode: 0644]
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jackrabbit/webdav/MultipleRepositoryHandlerMapping.java [new file with mode: 0644]
server/runtime/org.argeo.server.jcr/build.properties
server/runtime/org.argeo.server.jcr/pom.xml
server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/DefaultRepositoryRegister.java [new file with mode: 0644]
server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/RepositoryRegister.java [new file with mode: 0644]

index 069bf975842ab7dbca5dae73fe0582e77f28541c..e39bc56599e130d8fc01258826ff81e14bf990ea 100644 (file)
@@ -4,21 +4,28 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
 
 import javax.jcr.Item;
+import javax.jcr.LoginException;
 import javax.jcr.Node;
 import javax.jcr.NodeIterator;
 import javax.jcr.Property;
 import javax.jcr.PropertyIterator;
 import javax.jcr.PropertyType;
+import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.nodetype.NodeType;
 
 import org.argeo.ArgeoException;
+import org.argeo.eclipse.ui.TreeParent;
+import org.argeo.jcr.RepositoryRegister;
 import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.IStructuredContentProvider;
 import org.eclipse.jface.viewers.IStructuredSelection;
@@ -27,6 +34,7 @@ import org.eclipse.jface.viewers.LabelProvider;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.jface.viewers.TableViewer;
 import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.TreeNode;
 import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.jface.viewers.Viewer;
 import org.eclipse.swt.SWT;
@@ -44,7 +52,8 @@ public class GenericJcrBrowser extends ViewPart {
        private TreeViewer nodesViewer;
        private TableViewer propertiesViewer;
 
-       private Session jcrSession;
+       // private Session jcrSession;
+       private RepositoryRegister repositoryRegister;
 
        private Comparator<Item> itemComparator = new Comparator<Item>() {
                public int compare(Item o1, Item o2) {
@@ -87,11 +96,19 @@ public class GenericJcrBrowser extends ViewPart {
                                                }
                                        }
                                });
-               try {
-                       nodesViewer.setInput(jcrSession.getRootNode());
-               } catch (RepositoryException e) {
-                       throw new ArgeoException("Cannot initialize view", e);
-               }
+               nodesViewer.addDoubleClickListener(new IDoubleClickListener() {
+                       public void doubleClick(DoubleClickEvent event) {
+                               Object obj = ((IStructuredSelection) event.getSelection())
+                                               .getFirstElement();
+                               if (obj instanceof RepositoryNode) {
+                                       ((RepositoryNode) obj).login();
+                               } else if (obj instanceof WorkspaceNode) {
+                                       ((WorkspaceNode) obj).login();
+                               }
+
+                       }
+               });
+               nodesViewer.setInput(repositoryRegister);
 
                Composite bottom = new Composite(sashForm, SWT.NONE);
                bottom.setLayout(new GridLayout(1, false));
@@ -168,13 +185,29 @@ public class GenericJcrBrowser extends ViewPart {
                return new int[] { 70, 30 };
        }
 
-       public void setJcrSession(Session jcrSession) {
-               this.jcrSession = jcrSession;
+       public void setRepositoryRegister(RepositoryRegister repositoryRegister) {
+               this.repositoryRegister = repositoryRegister;
        }
 
        /*
         * NODES
         */
+       protected Object[] childrenNodes(Node parentNode) {
+               try {
+                       List<Node> children = new ArrayList<Node>();
+                       NodeIterator nit = parentNode.getNodes();
+                       while (nit.hasNext()) {
+                               Node node = nit.nextNode();
+                               children.add(node);
+                       }
+                       Node[] arr = children.toArray(new Node[children.size()]);
+                       Arrays.sort(arr, itemComparator);
+                       return arr;
+               } catch (RepositoryException e) {
+                       throw new ArgeoException("Cannot list children of " + parentNode, e);
+               }
+       }
+
        private class NodeContentProvider implements ITreeContentProvider {
 
                public Object[] getElements(Object inputElement) {
@@ -182,23 +215,32 @@ public class GenericJcrBrowser extends ViewPart {
                }
 
                public Object[] getChildren(Object parentElement) {
-                       try {
-                               if (parentElement instanceof Node) {
-                                       List<Node> children = new ArrayList<Node>();
-                                       NodeIterator nit = ((Node) parentElement).getNodes();
-                                       while (nit.hasNext()) {
-                                               Node node = nit.nextNode();
-                                               children.add(node);
-                                       }
-                                       Node[] arr = children.toArray(new Node[children.size()]);
-                                       Arrays.sort(arr, itemComparator);
-                                       return arr;
-                               } else {
-                                       return null;
+                       if (parentElement instanceof Node) {
+                               return childrenNodes((Node) parentElement);
+                       } else if (parentElement instanceof RepositoryNode) {
+                               return ((RepositoryNode) parentElement).getChildren();
+                       } else if (parentElement instanceof WorkspaceNode) {
+                               Session session = ((WorkspaceNode) parentElement).getSession();
+                               if (session == null)
+                                       return new Object[0];
+
+                               try {
+                                       return childrenNodes(session.getRootNode());
+                               } catch (RepositoryException e) {
+                                       throw new ArgeoException("Cannot retrieve root node of "
+                                                       + session, e);
                                }
-                       } catch (RepositoryException e) {
-                               throw new ArgeoException("Cannot retrieve children for "
-                                               + parentElement, e);
+                       } else if (parentElement instanceof RepositoryRegister) {
+                               RepositoryRegister repositoryRegister = (RepositoryRegister) parentElement;
+                               List<RepositoryNode> nodes = new ArrayList<RepositoryNode>();
+                               Map<String, Repository> repositories = repositoryRegister
+                                               .getRepositories();
+                               for (String name : repositories.keySet()) {
+                                       nodes.add(new RepositoryNode(name, repositories.get(name)));
+                               }
+                               return nodes.toArray();
+                       } else {
+                               return new Object[0];
                        }
                }
 
@@ -218,6 +260,10 @@ public class GenericJcrBrowser extends ViewPart {
                        try {
                                if (element instanceof Node) {
                                        return ((Node) element).hasNodes();
+                               } else if (element instanceof RepositoryNode) {
+                                       return ((RepositoryNode) element).hasChildren();
+                               } else if (element instanceof WorkspaceNode) {
+                                       return ((WorkspaceNode) element).getSession() != null;
                                }
                                return false;
                        } catch (RepositoryException e) {
@@ -297,4 +343,78 @@ public class GenericJcrBrowser extends ViewPart {
                }
 
        }
+
+       private class RepositoryNode extends TreeParent {
+               private final String name;
+               private final Repository repository;
+               private Session defaultSession = null;
+
+               public RepositoryNode(String name, Repository repository) {
+                       super(name);
+                       this.name = name;
+                       this.repository = repository;
+               }
+
+               public Repository getRepository() {
+                       return repository;
+               }
+
+               public Session getDefaultSession() {
+                       return defaultSession;
+               }
+
+               public void login() {
+                       try {
+                               defaultSession = repository.login();
+                               String[] wkpNames = defaultSession.getWorkspace()
+                                               .getAccessibleWorkspaceNames();
+                               for (String wkpName : wkpNames) {
+                                       if (wkpName.equals(defaultSession.getWorkspace().getName()))
+                                               addChild(new WorkspaceNode(repository, wkpName,
+                                                               defaultSession));
+                                       else
+                                               addChild(new WorkspaceNode(repository, wkpName));
+                               }
+                               nodesViewer.refresh(this);
+                       } catch (RepositoryException e) {
+                               throw new ArgeoException(
+                                               "Cannot connect to repository " + name, e);
+                       }
+               }
+       }
+
+       private class WorkspaceNode extends TreeParent {
+               private final String name;
+               private final Repository repository;
+               private Session session = null;
+
+               public WorkspaceNode(Repository repository, String name) {
+                       this(repository, name, null);
+               }
+
+               public WorkspaceNode(Repository repository, String name, Session session) {
+                       super(name);
+                       this.name = name;
+                       this.repository = repository;
+                       this.session = session;
+               }
+
+               public Session getSession() {
+                       return session;
+               }
+
+               public void login() {
+                       try {
+                               if (session != null)
+                                       session.logout();
+
+                               session = repository.login(name);
+                               nodesViewer.refresh(this);
+                       } catch (RepositoryException e) {
+                               throw new ArgeoException(
+                                               "Cannot connect to repository " + name, e);
+                       }
+               }
+
+       }
 }
diff --git a/server/modules/org.argeo.server.jackrabbit.webapp.war/.project b/server/modules/org.argeo.server.jackrabbit.webapp.war/.project
new file mode 100644 (file)
index 0000000..b3972fb
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.server.jackrabbit.webapp</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+       </natures>
+</projectDescription>
diff --git a/server/modules/org.argeo.server.jackrabbit.webapp.war/.settings/org.eclipse.pde.core.prefs b/server/modules/org.argeo.server.jackrabbit.webapp.war/.settings/org.eclipse.pde.core.prefs
new file mode 100644 (file)
index 0000000..ee0c8b2
--- /dev/null
@@ -0,0 +1,4 @@
+#Tue Feb 22 17:15:24 CET 2011
+eclipse.preferences.version=1
+pluginProject.extensions=false
+resolve.requirebundle=false
diff --git a/server/modules/org.argeo.server.jackrabbit.webapp.war/META-INF/MANIFEST.MF b/server/modules/org.argeo.server.jackrabbit.webapp.war/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..eadb4dc
--- /dev/null
@@ -0,0 +1,19 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Webapp
+Bundle-SymbolicName: org.argeo.server.jackrabbit.webapp
+Bundle-Version: 1.0.0.qualifier
+Web-ContextPath: jcr
+Bundle-Vendor: Argeo
+Import-Package: javax.jcr,
+ javax.servlet,
+ javax.servlet.http,
+ javax.servlet.resources,
+ org.argeo.jcr,
+ org.argeo.server.jackrabbit.webdav,
+ org.springframework.osgi.web.context.support;version="1.2.1",
+ org.springframework.security;version="2.0.6.RELEASE",
+ org.springframework.security.ui.webapp;version="2.0.6.RELEASE",
+ org.springframework.web.context;version="2.5.6.SEC01",
+ org.springframework.web.filter;version="2.5.6.SEC01",
+ org.springframework.web.servlet.handler;version="2.5.6.SEC01"
diff --git a/server/modules/org.argeo.server.jackrabbit.webapp.war/WEB-INF/applicationContext.xml b/server/modules/org.argeo.server.jackrabbit.webapp.war/WEB-INF/applicationContext.xml
new file mode 100644 (file)
index 0000000..1aec32e
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
+       xmlns:tx="http://www.springframework.org/schema/tx"
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
+       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
+
+       <import resource="osgi.xml" />
+       <import resource="security.xml" />
+
+       <bean id="repositoryRegister" class="org.argeo.jcr.DefaultRepositoryRegister" />
+
+</beans>
\ No newline at end of file
diff --git a/server/modules/org.argeo.server.jackrabbit.webapp.war/WEB-INF/osgi.xml b/server/modules/org.argeo.server.jackrabbit.webapp.war/WEB-INF/osgi.xml
new file mode 100644 (file)
index 0000000..80b804e
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<beans:beans xmlns="http://www.springframework.org/schema/osgi"\r
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"\r
+       xmlns:security="http://www.springframework.org/schema/security"\r
+       xsi:schemaLocation="http://www.springframework.org/schema/osgi  \r
+       http://www.springframework.org/schema/osgi/spring-osgi-1.1.xsd\r
+       http://www.springframework.org/schema/beans   \r
+       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\r
+       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">\r
+\r
+       <set id="repositories" interface="javax.jcr.Repository" cardinality="0..N">\r
+               <listener ref="repositoryRegister" bind-method="register"\r
+                       unbind-method="unregister" />\r
+       </set>\r
+\r
+       <reference id="_authenticationManager"\r
+               interface="org.springframework.security.AuthenticationManager" />\r
+</beans:beans>
\ No newline at end of file
diff --git a/server/modules/org.argeo.server.jackrabbit.webapp.war/WEB-INF/remoting-servlet.xml b/server/modules/org.argeo.server.jackrabbit.webapp.war/WEB-INF/remoting-servlet.xml
new file mode 100644 (file)
index 0000000..c77def2
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
+       xmlns:tx="http://www.springframework.org/schema/tx"
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
+       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
+
+       <bean
+               class="org.springframework.web.servlet.handler.SimpleServletPostProcessor" />
+
+       <bean id="servletHandler"
+               class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter" />
+
+       <bean id="urlMapping"
+               class="org.argeo.server.jackrabbit.webdav.MultipleRepositoryHandlerMapping">
+               <property name="repositoryRegister" ref="repositoryRegister" />
+       </bean>
+
+</beans>
\ No newline at end of file
diff --git a/server/modules/org.argeo.server.jackrabbit.webapp.war/WEB-INF/security.xml b/server/modules/org.argeo.server.jackrabbit.webapp.war/WEB-INF/security.xml
new file mode 100644 (file)
index 0000000..2e08bfd
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:security="http://www.springframework.org/schema/security"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">
+
+       <security:http>
+               <security:http-basic />
+               <security:intercept-url pattern="/**"
+                       access="ROLE_USER,ROLE_ADMIN,ROLE_ANONYMOUS" />
+       </security:http>
+</beans>
\ No newline at end of file
diff --git a/server/modules/org.argeo.server.jackrabbit.webapp.war/WEB-INF/web.xml b/server/modules/org.argeo.server.jackrabbit.webapp.war/WEB-INF/web.xml
new file mode 100644 (file)
index 0000000..b5a1509
--- /dev/null
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+       version="2.5">
+
+       <display-name>Argeo Jackrabbit Webapp</display-name>
+
+       <!-- General -->
+       <context-param>
+               <param-name>contextConfigLocation</param-name>
+               <param-value>/WEB-INF/applicationContext.xml</param-value>
+       </context-param>
+
+       <listener>
+               <display-name>Spring Context</display-name>
+               <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+       </listener>
+       <context-param>
+               <param-name>contextClass</param-name>
+               <param-value>org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext</param-value>
+       </context-param>
+
+       <!-- Remoting -->
+       <servlet>
+               <servlet-name>remoting</servlet-name>
+               <servlet-class>org.argeo.server.jackrabbit.webdav.ExtendedDispatcherServlet</servlet-class>
+               <init-param>
+                       <param-name>contextClass</param-name>
+                       <param-value>org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext</param-value>
+               </init-param>
+               <init-param>
+                       <param-name>dispatchOptionsRequest</param-name>
+                       <param-value>true</param-value>
+               </init-param>
+               <load-on-startup>1</load-on-startup>
+       </servlet>
+
+       <servlet-mapping>
+               <servlet-name>remoting</servlet-name>
+               <url-pattern>/remoting/*</url-pattern>
+       </servlet-mapping>
+
+       <!--  Security -->
+       <filter>
+               <filter-name>springSecurityFilterChain</filter-name>
+               <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
+       </filter>
+
+       <filter-mapping>
+               <filter-name>springSecurityFilterChain</filter-name>
+               <url-pattern>/*</url-pattern>
+       </filter-mapping>
+</web-app>
diff --git a/server/modules/org.argeo.server.jackrabbit.webapp.war/build.properties b/server/modules/org.argeo.server.jackrabbit.webapp.war/build.properties
new file mode 100644 (file)
index 0000000..5f22cdd
--- /dev/null
@@ -0,0 +1 @@
+bin.includes = META-INF/
index 1be03827a914aba67432d86df4d7a63729ca096f..6ec6065a542b7f2f3d8f422b9c6bfb9c7bef3609 100644 (file)
@@ -77,6 +77,8 @@ public class JackrabbitContainer implements InitializingBean, DisposableBean,
        /** Namespaces to register: key is prefix, value namespace */
        private Map<String, String> namespaces = new HashMap<String, String>();
 
+       private Boolean autocreateWorkspaces = false;
+
        public void afterPropertiesSet() throws Exception {
                // Load cnds as resources
                for (String resUrl : cndFiles) {
@@ -162,7 +164,10 @@ public class JackrabbitContainer implements InitializingBean, DisposableBean,
                try {
                        session = repository.login(credentials, workspaceName);
                } catch (NoSuchWorkspaceException e) {
-                       session = createWorkspaceAndLogsIn(credentials, workspaceName);
+                       if (autocreateWorkspaces)
+                               session = createWorkspaceAndLogsIn(credentials, workspaceName);
+                       else
+                               throw e;
                }
                processNewSession(session);
                return session;
@@ -181,7 +186,10 @@ public class JackrabbitContainer implements InitializingBean, DisposableBean,
                try {
                        session = repository.login(workspaceName);
                } catch (NoSuchWorkspaceException e) {
-                       session = createWorkspaceAndLogsIn(null, workspaceName);
+                       if (autocreateWorkspaces)
+                               session = createWorkspaceAndLogsIn(null, workspaceName);
+                       else
+                               throw e;
                }
                processNewSession(session);
                return session;
diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jackrabbit/webdav/CachingSessionProvider.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jackrabbit/webdav/CachingSessionProvider.java
new file mode 100644 (file)
index 0000000..ad30187
--- /dev/null
@@ -0,0 +1,57 @@
+package org.argeo.server.jackrabbit.webdav;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.LoginException;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.server.SessionProvider;
+
+public class CachingSessionProvider implements SessionProvider {
+       private static final String JCR_SESSIONS_ATTRIBUTE = "jcrSessions";
+
+       private final static Log log = LogFactory
+                       .getLog(CachingSessionProvider.class);
+
+       @SuppressWarnings("unchecked")
+       public Session getSession(HttpServletRequest request, Repository rep,
+                       String workspace) throws LoginException, ServletException,
+                       RepositoryException {
+               HttpSession httpSession = request.getSession();
+
+               if (httpSession.getAttribute(JCR_SESSIONS_ATTRIBUTE) == null) {
+                       httpSession
+                                       .setAttribute(JCR_SESSIONS_ATTRIBUTE, Collections
+                                                       .synchronizedMap(new HashMap<String, Session>()));
+               }
+               Map<String, Session> sessions = (Map<String, Session>) httpSession
+                               .getAttribute(JCR_SESSIONS_ATTRIBUTE);
+               if (!sessions.containsKey(workspace)) {
+                       Session session = rep.login(workspace);
+                       sessions.put(workspace, session);
+                       return session;
+               } else {
+                       Session session = sessions.get(workspace);
+                       if (!session.isLive()) {
+                               session = rep.login(workspace);
+                       }
+                       return session;
+               }
+       }
+
+       public void releaseSession(Session session) {
+               if (log.isDebugEnabled())
+                       log.debug("Releasing JCR session " + session);
+               session.logout();
+       }
+
+}
index 0db3dbda9be89cddca620cbe487426021eef7eb0..8c961c108b3c4df9863c0d5438381b3ba76b7d36 100644 (file)
@@ -26,7 +26,7 @@ import org.argeo.ArgeoException;
 import org.springframework.web.servlet.DispatcherServlet;
 
 public class ExtendedDispatcherServlet extends DispatcherServlet {
-       private static final long serialVersionUID = 1L;
+       private static final long serialVersionUID = -5584673209855752009L;
 
        private final static Log log = LogFactory
                        .getLog(ExtendedDispatcherServlet.class);
diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jackrabbit/webdav/JcrRemotingServlet.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jackrabbit/webdav/JcrRemotingServlet.java
new file mode 100644 (file)
index 0000000..8fb5801
--- /dev/null
@@ -0,0 +1,33 @@
+package org.argeo.server.jackrabbit.webdav;
+
+import java.util.Enumeration;
+
+import javax.jcr.Repository;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+
+import org.apache.jackrabbit.server.SessionProvider;
+import org.springframework.web.servlet.mvc.ServletWrappingController;
+
+public class JcrRemotingServlet extends
+               org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet {
+
+       private static final long serialVersionUID = 3131835511468341309L;
+
+       private final Repository repository;
+
+       public JcrRemotingServlet(Repository repository) {
+               this.repository = repository;
+       }
+
+       @Override
+       protected Repository getRepository() {
+               return repository;
+       }
+
+       @Override
+       protected SessionProvider getSessionProvider() {
+               return new CachingSessionProvider();
+       }
+
+}
diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jackrabbit/webdav/MultipleRepositoryHandlerMapping.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/server/jackrabbit/webdav/MultipleRepositoryHandlerMapping.java
new file mode 100644 (file)
index 0000000..077aa4f
--- /dev/null
@@ -0,0 +1,105 @@
+package org.argeo.server.jackrabbit.webdav;
+
+import java.util.Enumeration;
+import java.util.Properties;
+
+import javax.jcr.Repository;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.webdav.jcr.JCRWebdavServerServlet;
+import org.argeo.jcr.RepositoryRegister;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.web.context.ServletContextAware;
+import org.springframework.web.servlet.HandlerExecutionChain;
+import org.springframework.web.servlet.HandlerMapping;
+import org.springframework.web.servlet.mvc.ServletWrappingController;
+
+public class MultipleRepositoryHandlerMapping implements HandlerMapping,
+               ApplicationContextAware, ServletContextAware {
+       private final static Log log = LogFactory
+                       .getLog(MultipleRepositoryHandlerMapping.class);
+
+       private ConfigurableApplicationContext applicationContext;
+       private ServletContext servletContext;
+
+       private RepositoryRegister repositoryRegister;
+
+       public HandlerExecutionChain getHandler(HttpServletRequest request)
+                       throws Exception {
+               log.debug(request);
+               log.debug("getContextPath=" + request.getContextPath());
+               log.debug("getServletPath=" + request.getServletPath());
+               log.debug("getPathInfo=" + request.getPathInfo());
+
+               String repositoryName = "repo";
+               String pathPrefix = "/remoting/repo";
+               String beanName = "remoting_" + repositoryName;
+
+               if (!applicationContext.containsBean(beanName)) {
+                       Repository repository = repositoryRegister.getRepositories().get(
+                                       repositoryName);
+                       JcrRemotingServlet jcrRemotingServlet = new JcrRemotingServlet(
+                                       repository);
+                       Properties initParameters = new Properties();
+                       initParameters.setProperty(
+                                       JCRWebdavServerServlet.INIT_PARAM_RESOURCE_PATH_PREFIX,
+                                       pathPrefix);
+                       jcrRemotingServlet.init(new DelegatingServletConfig(beanName,
+                                       initParameters));
+                       applicationContext.getBeanFactory().registerSingleton(beanName,
+                                       jcrRemotingServlet);
+               }
+               HttpServlet remotingServlet = (HttpServlet) applicationContext
+                               .getBean(beanName);
+               return new HandlerExecutionChain(remotingServlet);
+       }
+
+       public void setApplicationContext(ApplicationContext applicationContext)
+                       throws BeansException {
+               this.applicationContext = (ConfigurableApplicationContext) applicationContext;
+       }
+
+       public void setServletContext(ServletContext servletContext) {
+               this.servletContext = servletContext;
+       }
+
+       public void setRepositoryRegister(RepositoryRegister repositoryRegister) {
+               this.repositoryRegister = repositoryRegister;
+       }
+
+       private class DelegatingServletConfig implements ServletConfig {
+               private String name;
+               private Properties initParameters;
+
+               public DelegatingServletConfig(String name, Properties initParameters) {
+                       super();
+                       this.name = name;
+                       this.initParameters = initParameters;
+               }
+
+               public String getServletName() {
+                       return name;
+               }
+
+               public ServletContext getServletContext() {
+                       return servletContext;
+               }
+
+               public String getInitParameter(String paramName) {
+                       return initParameters.getProperty(paramName);
+               }
+
+               public Enumeration getInitParameterNames() {
+                       return initParameters.keys();
+               }
+       }
+
+}
index 2f77ca90060eea0e4d5c75883d754f9ac1190721..a9dd55a1d4eac71e22dbd22e131ddd52165dc32f 100644 (file)
@@ -4,8 +4,7 @@ source.. = src/main/java/,\
 output.. = target/classes/
 bin.includes = META-INF/,\
                .
-additional.bundles = org.argeo.server.jackrabbit,\
-                     com.springsource.slf4j.api,\
+additional.bundles = com.springsource.slf4j.api,\
                      com.springsource.slf4j.log4j,\
                      com.springsource.org.apache.log4j,\
                      com.springsource.org.apache.commons.collections,\
index aa72e28701b86c4206c1fab2b0292eb7d6dda204..1d30016fa004c12ca38c1048594202de81ec8b77 100644 (file)
                        <groupId>org.springframework.ws</groupId>
                        <artifactId>org.springframework.xml</artifactId>
                </dependency>
+               
+               <!-- OSGi -->
+               <dependency>
+                       <groupId>org.eclipse.osgi</groupId>
+                       <artifactId>org.eclipse.osgi</artifactId>
+                       <scope>provided</scope>
+               </dependency>
 
                <!-- Logging -->
                <dependency>
diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/DefaultRepositoryRegister.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/DefaultRepositoryRegister.java
new file mode 100644 (file)
index 0000000..e2d9854
--- /dev/null
@@ -0,0 +1,72 @@
+package org.argeo.jcr;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Observable;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class DefaultRepositoryRegister extends Observable implements
+               RepositoryRegister {
+       private final static Log log = LogFactory
+                       .getLog(DefaultRepositoryRegister.class);
+
+       private SortedMap<String, Repository> repositories = Collections
+                       .synchronizedSortedMap(new TreeMap<String, Repository>());
+
+       @SuppressWarnings("rawtypes")
+       public synchronized Repository getRepository(Map parameters)
+                       throws RepositoryException {
+               if (!parameters.containsKey(JCR_REPOSITORY_NAME))
+                       throw new RepositoryException("Parameter " + JCR_REPOSITORY_NAME
+                                       + " has to be defined.");
+               String name = parameters.get(JCR_REPOSITORY_NAME).toString();
+               if (!repositories.containsKey(name))
+                       throw new RepositoryException("No repository registered with name "
+                                       + name);
+
+               return repositories.get(name);
+       }
+
+       public Map<String, Repository> getRepositories() {
+               return new TreeMap<String, Repository>(repositories);
+       }
+
+       /** Registers a service, typically called when OSGi services are bound. */
+       @SuppressWarnings("rawtypes")
+       public synchronized void register(Repository repository, Map properties) {
+               // TODO: also check bean name?
+               if (properties == null || !properties.containsKey(JCR_REPOSITORY_NAME)) {
+                       log.warn("Cannot register a repository without property "
+                                       + JCR_REPOSITORY_NAME);
+                       return;
+               }
+
+               String name = properties.get(JCR_REPOSITORY_NAME).toString();
+               repositories.put(name, repository);
+               setChanged();
+               notifyObservers(repository);
+       }
+
+       /** Unregisters a service, typically called when OSGi services are unbound. */
+       @SuppressWarnings("rawtypes")
+       public synchronized void unregister(Repository repository, Map properties) {
+               // TODO: also check bean name?
+               if (properties == null || !properties.containsKey(JCR_REPOSITORY_NAME)) {
+                       log.warn("Cannot unregister a repository without property "
+                                       + JCR_REPOSITORY_NAME);
+                       return;
+               }
+
+               String name = properties.get(JCR_REPOSITORY_NAME).toString();
+               repositories.remove(name);
+               setChanged();
+               notifyObservers(repository);
+       }
+}
diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/RepositoryRegister.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/RepositoryRegister.java
new file mode 100644 (file)
index 0000000..8d317db
--- /dev/null
@@ -0,0 +1,13 @@
+package org.argeo.jcr;
+
+import java.util.Map;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryFactory;
+
+/** Allows to register repositories by name. */
+public interface RepositoryRegister extends RepositoryFactory{
+       public final static String JCR_REPOSITORY_NAME = "argeo.jcr.repository.name";
+
+       public Map<String,Repository> getRepositories();
+}