2 * Copyright (c) 2018 Red Hat, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.aaa.web;
10 import java.util.List;
12 import javax.servlet.ServletContainerInitializer;
13 import javax.servlet.ServletContext;
14 import javax.servlet.ServletContextListener;
15 import javax.servlet.ServletRegistration;
16 import org.immutables.value.Value;
17 import org.immutables.value.Value.Default;
20 * Web Context with URL prefix. AKA Web App or Servlet context.
23 * Its {@link WebContextBuilder} allows programmatic web component registration
24 * (as opposed to declarative e.g. via web.xml, OSGi HTTP Whiteboard blueprint
25 * integration, CXF BP etc.)
28 * This is preferable because:
30 * <li>using code instead of hiding class names in XML enables tools such as
31 * e.g. BND (in the maven-bundle-plugin) to correctly figure dependencies e.g.
32 * for OSGi Import-Package headers;
34 * <li>explicit passing of web components instances, instead of providing class
35 * names in XML files and letting a web container create the new instances using
36 * the default constructor, solves a pesky dependency injection (DI) related
37 * problem which typically leads to weird hoops in code through
38 * <code>static</code> etc. that can be avoided using this;
40 * <li>tests can more easily programmatically instantiate web components.
44 * This, not surprisingly, looks somewhat like a Servlet (3.x)
45 * {@link ServletContext}, which also allows programmatic dynamic registration
46 * e.g. via {@link ServletRegistration}; however in practice direct use of that
47 * API has been found to be problematic under OSGi, because it is intended for
48 * JSE and <a href="https://github.com/eclipse/jetty.project/issues/1395">does
49 * not easily appear to permit dynamic registration at any time</a> (only during
50 * Servlet container initialization time by
51 * {@link ServletContainerInitializer}), and is generally less clear to use than
52 * this simple API which intentionally maps directly to what one would have
53 * declared in a web.xml file. This API is also slightly more focused and drops
54 * a number of concepts that API has which we do not want to support here
55 * (including e.g. security, roles, multipart etc.)
58 * It also looks somewhat similar to the OSGi HttpService, but we want to avoid
59 * any org.osgi dependency (both API and impl) here, and that API is also less
60 * clear (and uses an ancient (!) {@link java.util.Dictionary} in its method
61 * signature), and -most importantly- simply does not support Filters and Listeners, only
62 * Servlets. The Pax Web API does extend the base OSGi API and adds supports for
63 * Filters, Listeners and context parameters, but is still OSGi specific,
64 * whereas this offers a much simpler standalone API without OSGi dependency.
65 * (The Pax Web API also has confusing signatures in its registerFilter() methods,
66 * where one can easily confuse which String[] is the urlPatterns;
67 * which we had initially done accidentally; and left AAA broken.)
70 * This is immutable, with a Builder, because contrary to a declarative approach
71 * in a file such as web.xml, the registration order very much matters (e.g. an
72 * context parameter added after a Servlet registration would not be seen by that
73 * Servlet; or a Filter added to protect a Servlet might not yet be active
74 * for an instant if the registerServlet is before the registerFilter).
75 * Therefore, this API enforces atomicity and lets clients first register
76 * everything on the Builder, and only then use
77 * {@link WebServer#registerWebContext(WebContext)}.
79 * @author Michael Vorburger.ch
82 @Value.Style(visibility = Value.Style.ImplementationVisibility.PRIVATE, depluralize = true)
83 public abstract class WebContext {
85 public static WebContextBuilder builder() {
86 return new WebContextBuilder();
90 * Path which will be used as URL prefix to all registered servlets and filters.
92 public abstract String contextPath();
95 * Flag whether this context supports web sessions, defaults to true.
98 public boolean supportsSessions() {
105 public abstract List<ServletDetails> servlets();
110 public abstract List<FilterDetails> filters();
115 public abstract List<ServletContextListener> listeners();
118 * Registers resources (eg html files) that can be accessed via the URI namespace.
120 public abstract List<ResourceDetails> resources();
123 * Context params. NB: These are the web context's wide parameters; contrary to
124 * individual {@link ServletDetails#initParams()} and
125 * {@link FilterDetails#initParams()}.
127 public abstract Map<String, String> contextParams();
130 protected void check() {
131 servlets().forEach(servlet -> {
132 if (servlet.urlPatterns().isEmpty()) {
133 throw new IllegalArgumentException("Servlet has no URL: " + servlet.name());
136 filters().forEach(filter -> {
137 if (filter.urlPatterns().isEmpty()) {
138 throw new IllegalArgumentException("Filter has no URL: " + filter.name());