2 * ============LICENSE_START=======================================================
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
23 package org.onap.policy.common.endpoints.http.server.internal;
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;
37 * REST Jetty Server that uses Jersey Servlets to support JAX-RS Web Services.
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.
44 public class JettyJerseyServer extends JettyServletServer {
47 * Swagger API Base Path.
49 protected static final String SWAGGER_API_BASEPATH = "swagger.api.basepath";
54 protected static final String SWAGGER_CONTEXT_ID = "swagger.context.id";
59 protected static final String SWAGGER_SCANNER_ID = "swagger.scanner.id";
62 * Swagger Pretty Print.
64 protected static final String SWAGGER_PRETTY_PRINT = "swagger.pretty.print";
67 * Jersey GSON Classes Init Param Value.
69 protected static final String JERSEY_GSON_INIT_CLASSNAMES_PARAM_VALUE =
70 String.join(",", GsonMessageBodyHandler.class.getName(), JsonExceptionMapper.class.getName());
75 protected static Logger logger = LoggerFactory.getLogger(JettyJerseyServer.class);
80 protected String swaggerId = null;
83 * The serialization provider to be used when classes are added to the service.
85 private String classProvider = JERSEY_GSON_INIT_CLASSNAMES_PARAM_VALUE;
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
99 public JettyJerseyServer(String name, boolean https, String host, int port, boolean sniHostCheck,
100 String contextPath, boolean swagger) {
102 super(name, https, host, port, sniHostCheck, contextPath);
104 this.swaggerId = "swagger-" + this.port;
105 attachSwaggerServlet(https);
110 * Attaches a swagger initialization servlet.
112 protected void attachSwaggerServlet(boolean https) {
114 ServletContextHandler handler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
115 handler.setContextPath("/");
117 ServletHolder swaggerServlet = handler.addServlet(ServletContainer.class, "/*");
119 String hostname = this.connector.getHost();
120 if (StringUtils.isBlank(hostname) || hostname.equals(NetworkUtil.IPV4_WILDCARD_ADDRESS)) {
121 hostname = NetworkUtil.getHostname();
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);
131 if (logger.isDebugEnabled()) {
132 logger.debug("{}: Swagger Servlet has been attached: {}", this, swaggerServlet.dump());
137 * Retrieves cached server based on servlet path.
139 * @param servletPath servlet path
140 * @return the jetty servlet holder
142 * @throws IllegalArgumentException if invalid arguments are provided
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;
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");
158 if (servPath == null || servPath.isEmpty()) {
162 ServletHolder jerseyServlet = this.getServlet(servPath);
164 initStandardParams(jerseyServlet);
166 String initPackages = jerseyServlet.getInitParameter(ServerProperties.PROVIDER_PACKAGES);
167 if (initPackages == null) {
168 initPackages = restPackage;
171 initPackages += "," + restPackage;
174 jerseyServlet.setInitParameter(ServerProperties.PROVIDER_PACKAGES, initPackages);
176 if (logger.isDebugEnabled()) {
177 logger.debug("{}: added REST package: {}", this, jerseyServlet.dump());
182 public synchronized void addServletClass(String servletPath, String restClass) {
184 if (StringUtils.isBlank(restClass)) {
185 throw new IllegalArgumentException("No discoverable REST class provided");
188 if (servletPath == null || servletPath.isEmpty()) {
192 ServletHolder jerseyServlet = this.getServlet(servletPath);
194 initStandardParams(jerseyServlet);
196 String initClasses = jerseyServlet.getInitParameter(ServerProperties.PROVIDER_CLASSNAMES);
197 if (initClasses == null) {
198 initClasses = restClass;
201 initClasses += "," + restClass;
204 jerseyServlet.setInitParameter(ServerProperties.PROVIDER_CLASSNAMES, initClasses);
206 if (logger.isDebugEnabled()) {
207 logger.debug("{}: added REST class: {}", this, jerseyServlet.dump());
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
216 * @param jerseyServlet servlet into which parameters should be added
218 private void initStandardParams(ServletHolder jerseyServlet) {
219 String initClasses = jerseyServlet.getInitParameter(ServerProperties.PROVIDER_CLASSNAMES);
220 if (initClasses != null) {
224 initClasses = classProvider;
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);
233 jerseyServlet.setInitParameter(ServerProperties.PROVIDER_CLASSNAMES, initClasses);
235 jerseyServlet.setInitParameter(ServerProperties.METAINF_SERVICES_LOOKUP_DISABLE, "true");
239 * Note: this must be invoked <i>before</i> {@link #addServletClass(String, String)} or
240 * {@link #addServletPackage(String, String)}.
243 public void setSerializationProvider(String provider) {
244 classProvider = provider;
248 public String toString() {
249 return "JettyJerseyServer [Jerseyservlets=" + servlets
250 + ", swaggerId=" + swaggerId
251 + ", toString()=" + super.toString()