Document and validate web-api constructs
[aaa.git] / web / api / src / main / java / org / opendaylight / aaa / web / FilterDetails.java
1 /*
2  * Copyright (c) 2018 Red Hat, Inc. and others. All rights reserved.
3  *
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
7  */
8 package org.opendaylight.aaa.web;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.collect.ImmutableList;
13 import com.google.common.collect.ImmutableMap;
14 import java.util.List;
15 import java.util.Map;
16 import javax.servlet.Filter;
17 import org.eclipse.jdt.annotation.NonNull;
18
19 /**
20  * Details about a {@link Filter}.
21  *
22  * @author Michael Vorburger.ch
23  */
24 public interface FilterDetails {
25     /**
26      * Get a {@link Filter} instance.
27      *
28      * @return {@link Filter} instance
29      */
30     @NonNull Filter filter();
31
32     /**
33      * Get Filter's name.
34      *
35      * @return {@link String}
36      */
37     @NonNull String name();
38
39     /**
40      * Get list of Filter URL patterns. These patterns control where filter is applied.
41      *
42      * <p>
43      * Restrictions to URLs and how it should look like are next:
44      * <ul>
45      *   <li>A string beginning with a ‘ / ’ character and ending with a ‘ /*’ suffix is used for path mapping.</li>
46      *   <li>A string beginning with a ‘ *. ’ prefix is used as an extension mapping.</li>
47      *   <li>The empty string ("") is a special URL pattern that exactly maps to the application's context root, i.e.,
48      *       requests of the form {@code http://host:port/context-root/}. In this case the path info is ’ / ’ and the
49      *       servlet path and context path is empty string (““).</li>
50      *   <li>A string containing only the ’ / ’ character indicates the "default" servlet of the application. In this
51      *       case the servlet path is the request URI minus the context path and the path info is null.</li>
52      *   <li>All other strings are used for exact matches only.</li>
53      * </ul>
54      *
55      * @return {@link List} of Filter URL patterns
56      * @see "Java Servlet Specification Version 3.1, Section 12.2 Specification of Mappings"
57      */
58     @NonNull List<String> urlPatterns();
59
60     /**
61      * Get Filter initial parameters.
62      *
63      * @return {@link Map} that contains initial parameters
64      */
65     @NonNull Map<String, String> initParams();
66
67     /**
68      * Get indication whether {@link #filter()} supports asynchronous processing.
69      *
70      * @return {@code true} if the filter supports asynchronous processing
71      * @see "Java Servlet Specification Version 3.1, Section 2.3.3.3 Asynchronous Processing"
72      */
73     boolean asyncSupported();
74
75     /**
76      * Create a builder for {@link FilterDetails}.
77      *
78      * @return {@link Builder} builder instance
79      */
80     static @NonNull Builder builder() {
81         return new Builder();
82     }
83
84     /**
85      * Builds instances of type {@link FilterDetails FilterDetails}. Initialize attributes and then invoke the
86      * {@link #build()} method to create an immutable instance.
87      *
88      * <p><em>{@code FilterDetails.Builder} is not thread-safe and generally should not be stored in a field or
89      * collection, but instead used immediately to create instances.</em>
90      */
91     final class Builder {
92         private record ImmutableFilterDetails(Filter filter, String name, ImmutableList<String> urlPatterns,
93                 ImmutableMap<String, String> initParams, boolean asyncSupported) implements FilterDetails {
94             ImmutableFilterDetails {
95                 if (urlPatterns.isEmpty()) {
96                     throw new IllegalStateException("No urlPattern specified");
97                 }
98             }
99         }
100
101         private final ImmutableMap.Builder<String, String> initParams = ImmutableMap.builder();
102         private final ImmutableList.Builder<String> urlPatterns = ImmutableList.builder();
103         private Filter filter;
104         private String name;
105         private boolean asyncSupported;
106
107         private Builder() {
108             // Hidden on purpose
109         }
110
111         /**
112          * Initializes the value for the {@link FilterDetails#filter() filter} attribute.
113          *
114          * @param filter The value for filter
115          * @return {@code this} builder for use in a chained invocation
116          */
117         @SuppressWarnings("checkstyle:hiddenField")
118         public @NonNull Builder filter(final Filter filter) {
119             this.filter = requireNonNull(filter);
120             return this;
121         }
122
123         /**
124          * Initializes the value for the {@link FilterDetails#name() name} attribute.
125          *
126          * <p><em>If not set, this attribute will have a value corresponding to {@code filter().getClass().getName()}.
127          * </em>
128          *
129          * @param name The value for name
130          * @return {@code this} builder for use in a chained invocation
131          * @throws NullPointerException if {code name} is {@code null}
132          */
133         @SuppressWarnings("checkstyle:hiddenField")
134         public @NonNull Builder name(final String name) {
135             this.name = requireNonNull(name);
136             return this;
137         }
138
139         /**
140          * Adds one element to {@link FilterDetails#urlPatterns() urlPatterns} list.
141          *
142          * @param urlPattern A urlPatterns element
143          * @return {@code this} builder for use in a chained invocation
144          * @throws NullPointerException if {code urlPattern} is {@code null}
145          * @throws IllegalArgumentException if {@code urlPattern} does not meet specification criteria
146          */
147         public @NonNull Builder addUrlPattern(final String urlPattern) {
148             urlPatterns.add(ServletSpec.requireMappingSpec(urlPattern));
149             return this;
150         }
151
152         /**
153          * Put one entry to the {@link FilterDetails#initParams() initParams} map.
154          *
155          * @param key The key in the initParams map
156          * @param value The associated value in the initParams map
157          * @return {@code this} builder for use in a chained invocation
158          * @throws NullPointerException if any argument is {@code null}
159          */
160         public @NonNull Builder putInitParam(final String key, final String value) {
161             initParams.put(key, value);
162             return this;
163         }
164
165         /**
166          * Initializes the value for the {@link FilterDetails#asyncSupported() asyncSupported} attribute.
167          *
168          * <p><em>If not set, this attribute will have a default value of {@code false}.</em>
169          *
170          * @param asyncSupported The value for asyncSupported
171          * @return {@code this} builder for use in a chained invocation
172          */
173         @SuppressWarnings("checkstyle:hiddenField")
174         public @NonNull Builder asyncSupported(final boolean asyncSupported) {
175             this.asyncSupported = asyncSupported;
176             return this;
177         }
178
179         /**
180          * Builds a new {@link FilterDetails FilterDetails}.
181          *
182          * @return An immutable instance of FilterDetails
183          * @throws IllegalStateException if any required attributes are missing
184          */
185         public @NonNull FilterDetails build() {
186             if (filter == null) {
187                 throw new IllegalStateException("No filter specified");
188             }
189             return new ImmutableFilterDetails(filter, name != null ? name : filter.getClass().getName(),
190                 urlPatterns.build(), initParams.build(), asyncSupported);
191         }
192     }
193 }