Move away from AAA JettyWebserver to ODL Micro JettyWebServer implementation. 45/92445/4
authorVenkataSatya Jonnadula <ravi.jonnadula@gmail.com>
Mon, 14 Sep 2020 08:51:32 +0000 (14:21 +0530)
committerVenkataSatya Jonnadula <ravi.jonnadula@gmail.com>
Mon, 14 Sep 2020 10:31:00 +0000 (16:01 +0530)
The AAA JettyWebserver is hardcoded with Host as localhost.
So created new Impl in micro for JettyWebServer to fix this shortcomming.

JIRA: ODLMICRO-36

Signed-off-by: VenkataSatya Jonnadula <ravi.jonnadula@gmail.com>
Change-Id: Ief573a2180587c1f06a831442f80600615436c20

micro-core/src/main/java/org/opendaylight/infrautils/web/JettyWebServer.java [new file with mode: 0644]
micro-core/src/main/java/org/opendaylight/infrautils/web/WebModule.java

diff --git a/micro-core/src/main/java/org/opendaylight/infrautils/web/JettyWebServer.java b/micro-core/src/main/java/org/opendaylight/infrautils/web/JettyWebServer.java
new file mode 100644 (file)
index 0000000..9e60466
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2020 OpendayLight. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.infrautils.web;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.util.EnumSet;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Singleton;
+import javax.servlet.DispatcherType;
+import javax.servlet.ServletException;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.handler.ContextHandlerCollection;
+import org.eclipse.jetty.servlet.FilterHolder;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.opendaylight.aaa.web.WebContext;
+import org.opendaylight.aaa.web.WebContextRegistration;
+import org.opendaylight.aaa.web.WebServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link WebServer} (and {@link WebContext}) implementation based on Jetty.
+ * This implementation was added to overcome the shortcomings of AAA JettyWebServer,
+ * where some of the attributes like host are hardcoded to localhost. We will use this
+ * implementation for Aluminum as AAA for aluminum is already freezed. We Will probably
+ * move away from this Implementation once we remove hardcodings in AAA JettyWebserver.
+ *
+ * @author VenkataSatya
+ */
+@Singleton
+public class JettyWebServer implements WebServer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JettyWebServer.class);
+
+    private static final int HTTP_SERVER_IDLE_TIMEOUT = 30000;
+
+    private static final int HTTP_SERVER_PORT = 8181;
+
+    private int httpPort;
+    private final Server server;
+    private final ServerConnector http;
+    private final ContextHandlerCollection contextHandlerCollection;
+
+    public JettyWebServer() {
+        this(HTTP_SERVER_PORT);
+    }
+
+    public JettyWebServer(final int httpPort) {
+        checkArgument(httpPort >= 0, "httpPort must be positive");
+        checkArgument(httpPort < 65536, "httpPort must < 65536");
+
+        this.server = new Server();
+        server.setStopAtShutdown(true);
+
+        http = new ServerConnector(server);
+        http.setPort(httpPort);
+        http.setIdleTimeout(HTTP_SERVER_IDLE_TIMEOUT);
+        server.addConnector(http);
+
+        this.contextHandlerCollection = new ContextHandlerCollection();
+        server.setHandler(contextHandlerCollection);
+    }
+
+    @Override
+    public String getBaseURL() {
+        if (httpPort == 0) {
+            throw new IllegalStateException("must start() before getBaseURL()");
+        }
+        return "http://localhost:" + httpPort;
+    }
+
+    @PostConstruct
+    public void start() throws Exception {
+        server.start();
+        this.httpPort = http.getLocalPort();
+        LOG.info("Started Jetty-based HTTP web server on port {} ({}).", httpPort, hashCode());
+    }
+
+    @PreDestroy
+    public void stop() throws Exception {
+        LOG.info("Stopping Jetty-based web server...");
+        // NB server.stop() will call stop() on all ServletContextHandler/WebAppContext
+        server.stop();
+        LOG.info("Stopped Jetty-based web server.");
+    }
+
+    @Override
+    public synchronized WebContextRegistration registerWebContext(final WebContext webContext) throws ServletException {
+        String contextPathWithSlashPrefix =
+                webContext.contextPath().startsWith("/") ? webContext.contextPath() : "/" + webContext.contextPath();
+        ServletContextHandler handler = new ServletContextHandler(contextHandlerCollection, contextPathWithSlashPrefix,
+                webContext.supportsSessions() ? ServletContextHandler.SESSIONS : ServletContextHandler.NO_SESSIONS);
+
+        // The order in which we do things here must be the same as
+        // the equivalent in org.opendaylight.aaa.web.osgi.PaxWebServer
+
+        // 1. Context parameters - because listeners, filters and servlets could need
+        // them
+        webContext.contextParams().entrySet().forEach(entry -> handler.setAttribute(entry.getKey(), entry.getValue()));
+        // also handler.getServletContext().setAttribute(name, value), both seem work
+
+        // 2. Listeners - because they could set up things that filters and servlets
+        // need
+        webContext.listeners().forEach(listener -> handler.addEventListener(listener));
+
+        // 3. Filters - because subsequent servlets should already be covered by the
+        // filters
+        webContext.filters().forEach(filter -> {
+            FilterHolder filterHolder = new FilterHolder(filter.filter());
+            filterHolder.setInitParameters(filter.initParams());
+            filter.urlPatterns().forEach(
+                urlPattern -> handler.addFilter(filterHolder, urlPattern, EnumSet.allOf(DispatcherType.class)));
+        });
+
+        // 4. servlets - 'bout time for 'em by now, don't you think? ;)
+        webContext.servlets().forEach(servlet -> {
+            ServletHolder servletHolder = new ServletHolder(servlet.name(), servlet.servlet());
+            servletHolder.setInitParameters(servlet.initParams());
+            servletHolder.setInitOrder(1); // AKA <load-on-startup> 1
+            servlet.urlPatterns().forEach(urlPattern -> handler.addServlet(servletHolder, urlPattern));
+        });
+
+        restart(handler);
+
+        return () -> close(handler);
+    }
+
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    private static void restart(final AbstractLifeCycle lifecycle) throws ServletException {
+        try {
+            lifecycle.start();
+        } catch (ServletException | RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new ServletException("registerServlet() start failed", e);
+        }
+    }
+
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    private void close(final ServletContextHandler handler) {
+        try {
+            handler.stop();
+        } catch (Exception e) {
+            LOG.error("close() failed", e);
+        } finally {
+            handler.destroy();
+        }
+        contextHandlerCollection.removeHandler(handler);
+    }
+}
index 395e7f344c6c40293f16cb06b5b35678dd5d2d40..0af4e99c2a37327da0ff34c01733046919a5ba6b 100644 (file)
@@ -11,7 +11,6 @@ import com.google.inject.AbstractModule;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import org.opendaylight.aaa.web.WebContextSecurer;
 import org.opendaylight.aaa.web.WebServer;
-import org.opendaylight.aaa.web.jetty.JettyWebServer;
 import org.opendaylight.aaa.web.servlet.ServletSupport;
 import org.opendaylight.aaa.web.servlet.jersey2.JerseyServletSupport;
 
@@ -24,12 +23,10 @@ import org.opendaylight.aaa.web.servlet.jersey2.JerseyServletSupport;
 public class WebModule extends AbstractModule {
 
     // TODO note (new) org.opendaylight.aaa.web.testutils.WebTestModule .. integrate?
-//    private JettyWebServer webserver;
 
     @Override
     protected void configure() {
         // TODO read port from a -D parameter or configuration file instead of hard-coding
-//        webserver = new JettyWebServer(8181);
         bind(WebServer.class).to(JettyWebServer.class);
 
         // JAX-RS