d4c392b9641a27788e48ce39872b7a1033eb8143
[policy/common.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * policy-endpoints
4  * ================================================================================
5  * Copyright (C) 2017-2021 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2019-2020,2023 Nordix Foundation.
7  * Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.common.endpoints.http.server.internal;
24
25 import org.apache.commons.lang3.StringUtils;
26 import org.eclipse.jetty.servlet.ServletContextHandler;
27 import org.eclipse.jetty.servlet.ServletHolder;
28 import org.glassfish.jersey.server.ServerProperties;
29 import org.glassfish.jersey.servlet.ServletContainer;
30 import org.onap.policy.common.endpoints.http.server.JsonExceptionMapper;
31 import org.onap.policy.common.gson.GsonMessageBodyHandler;
32 import org.onap.policy.common.utils.network.NetworkUtil;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 /**
37  * REST Jetty Server that uses Jersey Servlets to support JAX-RS Web Services.
38  *
39  * <p>Note: the serialization provider will always be added to the server's class providers, as will the swagger
40  * providers (assuming swagger has been enabled). This happens whether {@link #addServletClass(String, String)} is used
41  * or {@link #addServletPackage(String, String)} is used. Thus, it's possible to have both the server's class provider
42  * property and the server's package provider property populated.
43  */
44 public class JettyJerseyServer extends JettyServletServer {
45
46     /**
47      * Swagger API Base Path.
48      */
49     protected static final String SWAGGER_API_BASEPATH = "swagger.api.basepath";
50
51     /**
52      * Swagger Context ID.
53      */
54     protected static final String SWAGGER_CONTEXT_ID = "swagger.context.id";
55
56     /**
57      * Swagger Scanner ID.
58      */
59     protected static final String SWAGGER_SCANNER_ID = "swagger.scanner.id";
60
61     /**
62      * Swagger Pretty Print.
63      */
64     protected static final String SWAGGER_PRETTY_PRINT = "swagger.pretty.print";
65
66     /**
67      * Jersey GSON Classes Init Param Value.
68      */
69     protected static final String JERSEY_GSON_INIT_CLASSNAMES_PARAM_VALUE =
70         String.join(",", GsonMessageBodyHandler.class.getName(), JsonExceptionMapper.class.getName());
71
72     /**
73      * Logger.
74      */
75     protected static Logger logger = LoggerFactory.getLogger(JettyJerseyServer.class);
76
77     /**
78      * Swagger ID.
79      */
80     protected String swaggerId = null;
81
82     /**
83      * The serialization provider to be used when classes are added to the service.
84      */
85     private String classProvider = JERSEY_GSON_INIT_CLASSNAMES_PARAM_VALUE;
86
87     /**
88      * Constructor.
89      *
90      * @param name name
91      * @param https enable https?
92      * @param host host server host
93      * @param port port server port
94      * @param sniHostCheck SNI Host checking flag
95      * @param swagger support swagger?
96      * @param contextPath context path
97      * @throws IllegalArgumentException in invalid arguments are provided
98      */
99     public JettyJerseyServer(String name, boolean https, String host, int port, boolean sniHostCheck,
100         String contextPath, boolean swagger) {
101
102         super(name, https, host, port, sniHostCheck, contextPath);
103         if (swagger) {
104             this.swaggerId = "swagger-" + this.port;
105             attachSwaggerServlet(https);
106         }
107     }
108
109     /**
110      * Attaches a swagger initialization servlet.
111      */
112     protected void attachSwaggerServlet(boolean https) {
113
114         ServletContextHandler handler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
115         handler.setContextPath("/");
116
117         ServletHolder swaggerServlet = handler.addServlet(ServletContainer.class, "/*");
118
119         String hostname = this.connector.getHost();
120         if (StringUtils.isBlank(hostname) || hostname.equals(NetworkUtil.IPV4_WILDCARD_ADDRESS)) {
121             hostname = NetworkUtil.getHostname();
122         }
123
124         swaggerServlet.setInitParameter(SWAGGER_API_BASEPATH,
125             ((https) ? "https://" : "http://") + hostname + ":" + this.connector.getPort() + "/");
126         swaggerServlet.setInitParameter(SWAGGER_CONTEXT_ID, swaggerId);
127         swaggerServlet.setInitParameter(SWAGGER_SCANNER_ID, swaggerId);
128         swaggerServlet.setInitParameter(SWAGGER_PRETTY_PRINT, "true");
129         swaggerServlet.setInitOrder(2);
130
131         if (logger.isDebugEnabled()) {
132             logger.debug("{}: Swagger Servlet has been attached: {}", this, swaggerServlet.dump());
133         }
134     }
135
136     /**
137      * Retrieves cached server based on servlet path.
138      *
139      * @param servletPath servlet path
140      * @return the jetty servlet holder
141      *
142      * @throws IllegalArgumentException if invalid arguments are provided
143      */
144     protected synchronized ServletHolder getServlet(String servletPath) {
145         ServletHolder jerseyServlet =
146             super.getServlet(org.glassfish.jersey.servlet.ServletContainer.class, servletPath);
147         jerseyServlet.setInitOrder(0);
148         return jerseyServlet;
149     }
150
151     @Override
152     public synchronized void addServletPackage(String servletPath, String restPackage) {
153         String servPath = servletPath;
154         if (StringUtils.isBlank(restPackage)) {
155             throw new IllegalArgumentException("No discoverable REST package provided");
156         }
157
158         if (servPath == null || servPath.isEmpty()) {
159             servPath = "/*";
160         }
161
162         ServletHolder jerseyServlet = this.getServlet(servPath);
163
164         initStandardParams(jerseyServlet);
165
166         String initPackages = jerseyServlet.getInitParameter(ServerProperties.PROVIDER_PACKAGES);
167         if (initPackages == null) {
168             initPackages = restPackage;
169
170         } else {
171             initPackages += "," + restPackage;
172         }
173
174         jerseyServlet.setInitParameter(ServerProperties.PROVIDER_PACKAGES, initPackages);
175
176         if (logger.isDebugEnabled()) {
177             logger.debug("{}: added REST package: {}", this, jerseyServlet.dump());
178         }
179     }
180
181     @Override
182     public synchronized void addServletClass(String servletPath, String restClass) {
183
184         if (StringUtils.isBlank(restClass)) {
185             throw new IllegalArgumentException("No discoverable REST class provided");
186         }
187
188         if (servletPath == null || servletPath.isEmpty()) {
189             servletPath = "/*";
190         }
191
192         ServletHolder jerseyServlet = this.getServlet(servletPath);
193
194         initStandardParams(jerseyServlet);
195
196         String initClasses = jerseyServlet.getInitParameter(ServerProperties.PROVIDER_CLASSNAMES);
197         if (initClasses == null) {
198             initClasses = restClass;
199
200         } else {
201             initClasses += "," + restClass;
202         }
203
204         jerseyServlet.setInitParameter(ServerProperties.PROVIDER_CLASSNAMES, initClasses);
205
206         if (logger.isDebugEnabled()) {
207             logger.debug("{}: added REST class: {}", this, jerseyServlet.dump());
208         }
209     }
210
211     /**
212      * Adds "standard" parameters to the initParameter set. Sets swagger parameters, if specified, and sets the class
213      * provider property. This can be invoked multiple times, but only the first actually causes any changes to the
214      * parameter set.
215      *
216      * @param jerseyServlet servlet into which parameters should be added
217      */
218     private void initStandardParams(ServletHolder jerseyServlet) {
219         String initClasses = jerseyServlet.getInitParameter(ServerProperties.PROVIDER_CLASSNAMES);
220         if (initClasses != null) {
221             return;
222         }
223
224         initClasses = classProvider;
225
226         if (this.swaggerId != null) {
227             jerseyServlet.setInitParameter("jersey.config.server.provider.packages",
228                 "io.swagger.v3.jaxrs2.integration.resources,io.swagger.sample.resource");
229             jerseyServlet.setInitParameter(SWAGGER_CONTEXT_ID, swaggerId);
230             jerseyServlet.setInitParameter(SWAGGER_SCANNER_ID, swaggerId);
231         }
232
233         jerseyServlet.setInitParameter(ServerProperties.PROVIDER_CLASSNAMES, initClasses);
234
235         jerseyServlet.setInitParameter(ServerProperties.METAINF_SERVICES_LOOKUP_DISABLE, "true");
236     }
237
238     /**
239      * Note: this must be invoked <i>before</i> {@link #addServletClass(String, String)} or
240      * {@link #addServletPackage(String, String)}.
241      */
242     @Override
243     public void setSerializationProvider(String provider) {
244         classProvider = provider;
245     }
246
247     @Override
248     public String toString() {
249         return "JettyJerseyServer [Jerseyservlets=" + servlets
250             + ", swaggerId=" + swaggerId
251             + ", toString()=" + super.toString()
252             + "]";
253     }
254 }