Move all JCR servlets to OSGi WhiteBoard.
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 5 Jun 2020 08:25:57 +0000 (10:25 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 5 Jun 2020 08:25:57 +0000 (10:25 +0200)
13 files changed:
org.argeo.cms/OSGI-INF/dataServletContext.xml [new file with mode: 0644]
org.argeo.cms/OSGI-INF/jcrServletContext.xml [new file with mode: 0644]
org.argeo.cms/bnd.bnd
org.argeo.cms/src/org/argeo/cms/internal/http/CmsRemotingServlet.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/http/CmsServletContextHelper.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/http/CmsSessionProvider.java
org.argeo.cms/src/org/argeo/cms/internal/http/CmsWebDavServlet.java
org.argeo.cms/src/org/argeo/cms/internal/http/DataHttpContext.java
org.argeo.cms/src/org/argeo/cms/internal/http/PrivateHttpContext.java
org.argeo.cms/src/org/argeo/cms/internal/http/PrivateServletContextHelper.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/RepositoryServiceFactory.java

diff --git a/org.argeo.cms/OSGI-INF/dataServletContext.xml b/org.argeo.cms/OSGI-INF/dataServletContext.xml
new file mode 100644 (file)
index 0000000..1c31adb
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="org.argeo.cms.dataServletContext">
+   <implementation class="org.argeo.cms.internal.http.CmsServletContextHelper"/>
+   <service>
+      <provide interface="org.osgi.service.http.context.ServletContextHelper"/>
+   </service>
+   <property name="osgi.http.whiteboard.context.name" type="String" value="dataServletContext"/>
+   <property name="osgi.http.whiteboard.context.path" type="String" value="/data"/>
+</scr:component>
diff --git a/org.argeo.cms/OSGI-INF/jcrServletContext.xml b/org.argeo.cms/OSGI-INF/jcrServletContext.xml
new file mode 100644 (file)
index 0000000..fb6f79e
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="org.argeo.cms.jcrServletContext">
+   <implementation class="org.argeo.cms.internal.http.PrivateServletContextHelper"/>
+   <service>
+      <provide interface="org.osgi.service.http.context.ServletContextHelper"/>
+   </service>
+   <property name="osgi.http.whiteboard.context.name" type="String" value="jcrServletContext"/>
+   <property name="osgi.http.whiteboard.context.path" type="String" value="/jcr"/>
+</scr:component>
index 4eae650a3437ad6cd9d40b5f333f5c9f0760762c..c176647859c2e03a71db2c718b3a404e5f1a624f 100644 (file)
@@ -11,6 +11,8 @@ org.osgi.*;version=0.0.0,\
 *
 
 Service-Component: OSGI-INF/cmsUserManager.xml,\
+OSGI-INF/jcrServletContext.xml,\
+OSGI-INF/dataServletContext.xml,\
 OSGI-INF/filesServletContext.xml,\
 OSGI-INF/filesServlet.xml
 
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/http/CmsRemotingServlet.java b/org.argeo.cms/src/org/argeo/cms/internal/http/CmsRemotingServlet.java
new file mode 100644 (file)
index 0000000..1bda6c7
--- /dev/null
@@ -0,0 +1,44 @@
+package org.argeo.cms.internal.http;
+
+import java.util.Map;
+
+import javax.jcr.Repository;
+
+import org.apache.jackrabbit.server.SessionProvider;
+import org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet;
+import org.argeo.api.NodeConstants;
+
+/** A {@link JcrRemotingServlet} based on {@link CmsSessionProvider}. */
+public class CmsRemotingServlet extends JcrRemotingServlet {
+       private static final long serialVersionUID = 6459455509684213633L;
+       private Repository repository;
+       private SessionProvider sessionProvider;
+
+       public CmsRemotingServlet() {
+       }
+
+       public CmsRemotingServlet(String alias, Repository repository) {
+               this.repository = repository;
+               this.sessionProvider = new CmsSessionProvider(alias);
+       }
+
+       @Override
+       public Repository getRepository() {
+               return repository;
+       }
+
+       public void setRepository(Repository repository, Map<String, String> properties) {
+               this.repository = repository;
+               String alias = properties.get(NodeConstants.CN);
+               if (alias != null)
+                       sessionProvider = new CmsSessionProvider(alias);
+               else
+                       throw new IllegalArgumentException("Only aliased repositories are supported");
+       }
+
+       @Override
+       protected SessionProvider getSessionProvider() {
+               return sessionProvider;
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/http/CmsServletContextHelper.java b/org.argeo.cms/src/org/argeo/cms/internal/http/CmsServletContextHelper.java
new file mode 100644 (file)
index 0000000..e2fd3d9
--- /dev/null
@@ -0,0 +1,72 @@
+package org.argeo.cms.internal.http;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Map;
+
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.NodeConstants;
+import org.argeo.cms.auth.HttpRequestCallbackHandler;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.service.http.context.ServletContextHelper;
+
+/**
+ * Default servlet context degrading to anonymous if the the sesison is not
+ * pre-authenticated.
+ */
+public class CmsServletContextHelper extends ServletContextHelper {
+       private final static Log log = LogFactory.getLog(CmsServletContextHelper.class);
+       // use CMS bundle for resources
+       private Bundle bundle = FrameworkUtil.getBundle(getClass());
+
+       public void init(Map<String, String> properties) {
+
+       }
+
+       public void destroy() {
+
+       }
+
+       @Override
+       public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
+               if (log.isTraceEnabled())
+                       HttpUtils.logRequestHeaders(log, request);
+               LoginContext lc;
+               try {
+                       lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, new HttpRequestCallbackHandler(request, response));
+                       lc.login();
+               } catch (LoginException e) {
+                       lc = processUnauthorized(request, response);
+                       if (lc == null)
+                               return false;
+               }
+               return true;
+       }
+
+       protected LoginContext processUnauthorized(HttpServletRequest request, HttpServletResponse response) {
+               // anonymous
+               try {
+                       LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS,
+                                       new HttpRequestCallbackHandler(request, response));
+                       lc.login();
+                       return lc;
+               } catch (LoginException e1) {
+                       if (log.isDebugEnabled())
+                               log.error("Cannot log in as anonymous", e1);
+                       return null;
+               }
+       }
+
+       @Override
+       public URL getResource(String name) {
+               return bundle.getResource(name);
+       }
+
+}
index a6ed7d884f43fd862476d44d2a213b981b883efc..f21f72441c0c549f349bf98ef838b0452789ef28 100644 (file)
@@ -43,6 +43,8 @@ public class CmsSessionProvider implements SessionProvider, Serializable {
                if (log.isTraceEnabled()) {
                        log.trace("Get JCR session from " + cmsSession);
                }
+               if (cmsSession == null)
+                       throw new IllegalStateException("Cannot find a session for request " + request.getRequestURI());
                Session session = cmsSession.getDataSession(alias, workspace, rep);
                cmsSessions.put(session, cmsSession);
                return session;
index f60e3b6043f4f272417489dc18ae1838b76e33aa..d61e5f49403fa99e0195cf154147b55758a648ca 100644 (file)
@@ -7,10 +7,19 @@ import javax.jcr.Repository;
 import org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet;
 import org.argeo.api.NodeConstants;
 
+/** A {@link SimpleWebdavServlet} based on {@link CmsSessionProvider}. */
 public class CmsWebDavServlet extends SimpleWebdavServlet {
        private static final long serialVersionUID = 7485800288686328063L;
        private Repository repository;
 
+       public CmsWebDavServlet() {
+       }
+
+       public CmsWebDavServlet(String alias, Repository repository) {
+               this.repository = repository;
+               setSessionProvider(new CmsSessionProvider(alias));
+       }
+
        @Override
        public Repository getRepository() {
                return repository;
@@ -21,6 +30,8 @@ public class CmsWebDavServlet extends SimpleWebdavServlet {
                String alias = properties.get(NodeConstants.CN);
                if (alias != null)
                        setSessionProvider(new CmsSessionProvider(alias));
+               else
+                       throw new IllegalArgumentException("Only aliased repositories are supported");
        }
 
 }
index df469524dece5d5d5fafef54d03280956cd8e24f..edc6326d7e512624a4868230a3940c73a2b9ee44 100644 (file)
@@ -16,6 +16,7 @@ import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.service.http.HttpContext;
 
+@Deprecated
 public class DataHttpContext implements HttpContext {
        private final static Log log = LogFactory.getLog(DataHttpContext.class);
 
index c3f2a1c802d1d8fd401d61261ba23ae7909fe6bc..793478c7187830054a6e76bc9bab4dd4700b8002 100644 (file)
@@ -5,6 +5,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 /** Requests authorisation */
+@Deprecated
 public class PrivateHttpContext extends DataHttpContext {
 
        public PrivateHttpContext(String httpAuthrealm, boolean forceBasic) {
index 62e74c34fcad2d889b5d31a391485442cd6a739e..b5dc7ba6f7586f637d43c0524a77f05ff37d8d7c 100644 (file)
@@ -1,53 +1,19 @@
 package org.argeo.cms.internal.http;
 
-import java.io.IOException;
-import java.net.URL;
-import java.util.Map;
-
 import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.api.NodeConstants;
-import org.argeo.cms.auth.HttpRequestCallbackHandler;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.service.http.context.ServletContextHelper;
-
-public class PrivateServletContextHelper extends ServletContextHelper {
-       private final static Log log = LogFactory.getLog(PrivateServletContextHelper.class);
-
+/** Servlet context forcing authentication. */
+public class PrivateServletContextHelper extends CmsServletContextHelper {
        // TODO make it configurable
        private final String httpAuthRealm = "Argeo";
        private final boolean forceBasic = false;
 
-       // use CMS bundle for resources
-       private Bundle bundle = FrameworkUtil.getBundle(getClass());
-
-       public void init(Map<String, String> properties) {
-
-       }
-
-       public void destroy() {
-
-       }
-
        @Override
-       public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
-               if (log.isTraceEnabled())
-                       HttpUtils.logRequestHeaders(log, request);
-               LoginContext lc;
-               try {
-                       lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, new HttpRequestCallbackHandler(request, response));
-                       lc.login();
-               } catch (LoginException e) {
-                       askForWwwAuth(request, response);
-                       return false;
-               }
-               return true;
+       protected LoginContext processUnauthorized(HttpServletRequest request, HttpServletResponse response) {
+               askForWwwAuth(request, response);
+               return null;
        }
 
        protected void askForWwwAuth(HttpServletRequest request, HttpServletResponse response) {
@@ -68,10 +34,4 @@ public class PrivateServletContextHelper extends ServletContextHelper {
                // response.setContentType("text/html; charset=UTF-8");
 
        }
-
-       @Override
-       public URL getResource(String name) {
-               return bundle.getResource(name);
-       }
-
 }
index 34d6e1f2482cac3cce54234f8eee249204dd6bdc..51feed9214aeab6065217a125acaf17bc1037259 100644 (file)
@@ -1,6 +1,7 @@
 package org.argeo.cms.internal.kernel;
 
 import static org.argeo.api.DataModelNamespace.CMS_DATA_MODEL_NAMESPACE;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX;
 
 import java.io.File;
 import java.io.IOException;
@@ -8,6 +9,8 @@ import java.io.InputStreamReader;
 import java.io.Reader;
 import java.lang.management.ManagementFactory;
 import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -20,6 +23,7 @@ import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.security.auth.callback.CallbackHandler;
+import javax.servlet.Servlet;
 import javax.transaction.UserTransaction;
 
 import org.apache.commons.logging.Log;
@@ -35,6 +39,9 @@ import org.argeo.api.security.CryptoKeyring;
 import org.argeo.api.security.Keyring;
 import org.argeo.cms.ArgeoNames;
 import org.argeo.cms.CmsException;
+import org.argeo.cms.internal.http.CmsRemotingServlet;
+import org.argeo.cms.internal.http.CmsWebDavServlet;
+import org.argeo.cms.internal.http.HttpUtils;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.osgi.useradmin.UserAdminConf;
 import org.argeo.util.LangUtils;
@@ -51,6 +58,8 @@ import org.osgi.framework.wiring.BundleWiring;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.cm.ManagedService;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
 import org.osgi.service.useradmin.Group;
 import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.UserAdmin;
@@ -68,7 +77,8 @@ public class CmsDeployment implements NodeDeployment {
 
 //     private final boolean cleanState;
 
-       private NodeHttp nodeHttp;
+//     private NodeHttp nodeHttp;
+       private String webDavConfig = HttpUtils.WEBDAV_CONFIG;
 
        private boolean argeoDataModelExtensionsAvailable = false;
 
@@ -86,19 +96,22 @@ public class CmsDeployment implements NodeDeployment {
 //             NodeState nodeState = bc.getService(nodeStateSr);
 //             cleanState = nodeState.isClean();
 
-               nodeHttp = new NodeHttp();
+//             nodeHttp = new NodeHttp();
                dataModels = new DataModels(bc);
                initTrackers();
        }
 
        private void initTrackers() {
-               ServiceTracker<?, ?> httpSt = new ServiceTracker<NodeHttp, NodeHttp>(bc, NodeHttp.class, null) {
+               ServiceTracker<?, ?> httpSt = new ServiceTracker<HttpService, HttpService>(bc, HttpService.class, null) {
 
                        @Override
-                       public NodeHttp addingService(ServiceReference<NodeHttp> reference) {
+                       public HttpService addingService(ServiceReference<HttpService> sr) {
                                httpAvailable = true;
+                               Object httpPort = sr.getProperty("http.port");
+                               Object httpsPort = sr.getProperty("https.port");
+                               log.info(httpPortsMsg(httpPort, httpsPort));
                                checkReadiness();
-                               return super.addingService(reference);
+                               return super.addingService(sr);
                        }
                };
                // httpSt.open();
@@ -161,6 +174,10 @@ public class CmsDeployment implements NodeDeployment {
                KernelUtils.asyncOpen(confAdminSt);
        }
 
+       private String httpPortsMsg(Object httpPort, Object httpsPort) {
+               return (httpPort != null ? "HTTP " + httpPort + " " : " ") + (httpsPort != null ? "HTTPS " + httpsPort : "");
+       }
+
        private void addStandardSystemRoles(UserAdmin userAdmin) {
                // we assume UserTransaction is already available (TODO make it more robust)
                UserTransaction userTransaction = bc.getService(bc.getServiceReference(UserTransaction.class));
@@ -195,8 +212,8 @@ public class CmsDeployment implements NodeDeployment {
        }
 
        public void shutdown() {
-               if (nodeHttp != null)
-                       nodeHttp.destroy();
+//             if (nodeHttp != null)
+//                     nodeHttp.destroy();
 
                try {
                        for (ServiceReference<JackrabbitLocalRepository> sr : bc
@@ -418,6 +435,9 @@ public class CmsDeployment implements NodeDeployment {
                        classes = new String[] { Repository.class.getName(), LocalRepository.class.getName() };
                }
                bc.registerService(classes, localRepository, properties);
+
+               // TODO make it configurable
+               registerRepositoryServlets(dataModelName, localRepository);
                if (log.isTraceEnabled())
                        log.trace("Published data model " + dataModelName);
        }
@@ -431,6 +451,54 @@ public class CmsDeployment implements NodeDeployment {
                return availableSince != null;
        }
 
+       protected void registerRepositoryServlets(String alias, Repository repository) {
+               registerRemotingServlet(alias, repository);
+               registerWebdavServlet(alias, repository);
+       }
+
+       protected void registerWebdavServlet(String alias, Repository repository) {
+               CmsWebDavServlet webdavServlet = new CmsWebDavServlet(alias, repository);
+               Hashtable<String, String> ip = new Hashtable<>();
+               ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsWebDavServlet.INIT_PARAM_RESOURCE_CONFIG, webDavConfig);
+               ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsWebDavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX,
+                               "/" + alias);
+
+               ip.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/" + alias + "/*");
+               ip.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT,
+                               "(" + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH + "=" + NodeConstants.PATH_DATA + ")");
+               bc.registerService(Servlet.class, webdavServlet, ip);
+       }
+
+       protected void registerRemotingServlet(String alias, Repository repository) {
+               CmsRemotingServlet remotingServlet = new CmsRemotingServlet(alias, repository);
+               Hashtable<String, String> ip = new Hashtable<>();
+               ip.put(NodeConstants.CN, alias);
+               // Properties ip = new Properties();
+               ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsRemotingServlet.INIT_PARAM_RESOURCE_PATH_PREFIX,
+                               "/" + alias);
+               ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsRemotingServlet.INIT_PARAM_AUTHENTICATE_HEADER,
+                               "Negotiate");
+
+               // Looks like a bug in Jackrabbit remoting init
+               Path tmpDir;
+               try {
+                       tmpDir = Files.createTempDirectory("remoting_" + alias);
+               } catch (IOException e) {
+                       throw new CmsException("Cannot create temp directory for remoting servlet", e);
+               }
+               ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsRemotingServlet.INIT_PARAM_HOME, tmpDir.toString());
+               ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsRemotingServlet.INIT_PARAM_TMP_DIRECTORY,
+                               "remoting_" + alias);
+               ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsRemotingServlet.INIT_PARAM_PROTECTED_HANDLERS_CONFIG,
+                               HttpUtils.DEFAULT_PROTECTED_HANDLERS);
+               ip.put(HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + CmsRemotingServlet.INIT_PARAM_CREATE_ABSOLUTE_URI, "false");
+
+               ip.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/" + alias + "/*");
+               ip.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT,
+                               "(" + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH + "=" + NodeConstants.PATH_JCR + ")");
+               bc.registerService(Servlet.class, remotingServlet, ip);
+       }
+
        private class RepositoryContextStc extends ServiceTracker<RepositoryContext, RepositoryContext> {
 
                public RepositoryContextStc() {
@@ -446,6 +514,7 @@ public class CmsDeployment implements NodeDeployment {
                                        prepareNodeRepository(repoContext.getRepository());
                                        // TODO separate home repository
                                        prepareHomeRepository(repoContext.getRepository());
+                                       registerRepositoryServlets(cn, repoContext.getRepository());
                                        nodeAvailable = true;
                                        checkReadiness();
                                } else {
index 87b688a6dd70e38c364802f2ea55f0cdc98f9339..ded4ae10e9cb8b60437e240c2b4e74ff0372fb6a 100644 (file)
@@ -34,6 +34,7 @@ import org.osgi.util.tracker.ServiceTracker;
  * Intercepts and enriches http access, mainly focusing on security and
  * transactionality.
  */
+@Deprecated
 public class NodeHttp implements KernelConstants {
        private final static Log log = LogFactory.getLog(NodeHttp.class);
 
index 5189512e48b239bc5dfa820d4b054f345e22ca6e..27e5199221212136428238f1adc5f444448f64d8 100644 (file)
@@ -1,18 +1,29 @@
 package org.argeo.cms.internal.kernel;
 
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX;
+
+import java.io.IOException;
 import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Dictionary;
 import java.util.HashMap;
+import java.util.Hashtable;
 import java.util.Map;
 
 import javax.jcr.Repository;
 import javax.jcr.RepositoryFactory;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.jackrabbit.core.RepositoryContext;
+import org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet;
 import org.argeo.api.NodeConstants;
 import org.argeo.cms.CmsException;
+import org.argeo.cms.internal.http.CmsRemotingServlet;
+import org.argeo.cms.internal.http.HttpUtils;
 import org.argeo.cms.internal.jcr.RepoConf;
 import org.argeo.cms.internal.jcr.RepositoryBuilder;
 import org.argeo.util.LangUtils;
@@ -21,7 +32,10 @@ import org.osgi.framework.Constants;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.service.cm.ConfigurationException;
 import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.http.NamespaceException;
+import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
 
+/** A {@link ManagedServiceFactory} creating or referencing JCR repositories. */
 class RepositoryServiceFactory implements ManagedServiceFactory {
        private final static Log log = LogFactory.getLog(RepositoryServiceFactory.class);
        private final BundleContext bc = FrameworkUtil.getBundle(RepositoryServiceFactory.class).getBundleContext();
@@ -91,7 +105,8 @@ class RepositoryServiceFactory implements ManagedServiceFactory {
 
                                        // home
                                        if (cn.equals(NodeConstants.NODE_REPOSITORY)) {
-                                               Dictionary<String, Object> homeProps = LangUtils.dico(NodeConstants.CN, NodeConstants.EGO_REPOSITORY);
+                                               Dictionary<String, Object> homeProps = LangUtils.dico(NodeConstants.CN,
+                                                               NodeConstants.EGO_REPOSITORY);
                                                EgoRepository homeRepository = new EgoRepository(repository, true);
                                                bc.registerService(Repository.class, homeRepository, homeProps);
                                        }
@@ -126,4 +141,5 @@ class RepositoryServiceFactory implements ManagedServiceFactory {
                        }
                }
        }
+
 }