2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
6 * Modifications Copyright (C) 2019-2020 Nordix Foundation.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.common.endpoints.http.server.internal;
24 import io.swagger.jersey.config.JerseyJaxrsConfig;
25 import java.util.HashMap;
26 import org.apache.commons.lang3.StringUtils;
27 import org.eclipse.jetty.servlet.DefaultServlet;
28 import org.eclipse.jetty.servlet.ServletHolder;
29 import org.glassfish.jersey.server.ServerProperties;
30 import org.onap.policy.common.utils.network.NetworkUtil;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
35 * REST Jetty Server that uses Jersey Servlets to support JAX-RS Web Services.
37 * <p>Note: the serialization provider will always be added to the server's class providers, as will the swagger
38 * providers (assuming swagger has been enabled). This happens whether {@link #addServletClass(String, String)} is used
39 * or {@link #addServletPackage(String, String)} is used. Thus it's possible to have both the server's class provider
40 * property and the server's package provider property populated.
42 public class JettyJerseyServer extends JettyServletServer {
45 * Swagger API Base Path.
47 protected static final String SWAGGER_API_BASEPATH = "swagger.api.basepath";
52 protected static final String SWAGGER_CONTEXT_ID = "swagger.context.id";
57 protected static final String SWAGGER_SCANNER_ID = "swagger.scanner.id";
60 * Swagger Pretty Print.
62 protected static final String SWAGGER_PRETTY_PRINT = "swagger.pretty.print";
65 * Jersey Jackson Classes Init Param Value.
67 protected static final String JERSEY_JACKSON_INIT_CLASSNAMES_PARAM_VALUE =
68 "org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJsonProvider";
71 * Jersey Swagger Classes Init Param Value.
73 protected static final String SWAGGER_INIT_CLASSNAMES_PARAM_VALUE =
74 "io.swagger.jaxrs.listing.ApiListingResource," + "io.swagger.jaxrs.listing.SwaggerSerializers";
77 * Servlet Holder Resource Base Path.
79 protected static final String SERVLET_HOLDER_RESOURCE_BASE = "resourceBase";
82 * Servlet Holder Directory Allowed.
84 protected static final String SERVLET_HOLDER_DIR_ALLOWED = "dirAllowed";
87 * Servlet Holder Path Information Only.
89 protected static final String SERVLET_HOLDER_PATH_INFO_ONLY = "pathInfoOnly";
94 protected static Logger logger = LoggerFactory.getLogger(JettyJerseyServer.class);
97 * Container for jersey servlets.
99 protected HashMap<String, ServletHolder> jerseyServlets = new HashMap<>();
102 * Container for default servlets.
104 protected HashMap<String, ServletHolder> defaultServlets = new HashMap<>();
109 protected String swaggerId = null;
112 * The serialization provider to be used when classes are added to the service.
114 private String classProvider = JERSEY_JACKSON_INIT_CLASSNAMES_PARAM_VALUE;
120 * @param https enable https?
121 * @param host host server host
122 * @param port port server port
123 * @param swagger support swagger?
124 * @param contextPath context path
126 * @throws IllegalArgumentException in invalid arguments are provided
128 public JettyJerseyServer(String name, boolean https, String host, int port, String contextPath, boolean swagger) {
130 super(name, https, host, port, contextPath);
132 this.swaggerId = "swagger-" + this.port;
133 attachSwaggerServlet(https);
138 * Attaches a swagger initialization servlet.
140 protected void attachSwaggerServlet(boolean https) {
142 ServletHolder swaggerServlet = context.addServlet(JerseyJaxrsConfig.class, "/");
144 String hostname = this.connector.getHost();
145 if (StringUtils.isBlank(hostname) || hostname.equals(NetworkUtil.IPV4_WILDCARD_ADDRESS)) {
146 hostname = NetworkUtil.getHostname();
149 swaggerServlet.setInitParameter(SWAGGER_API_BASEPATH,
150 ((https) ? "https://" : "http://") + hostname + ":" + this.connector.getPort() + "/");
151 swaggerServlet.setInitParameter(SWAGGER_CONTEXT_ID, swaggerId);
152 swaggerServlet.setInitParameter(SWAGGER_SCANNER_ID, swaggerId);
153 swaggerServlet.setInitParameter(SWAGGER_PRETTY_PRINT, "true");
154 swaggerServlet.setInitOrder(2);
156 if (logger.isDebugEnabled()) {
157 logger.debug("{}: Swagger Servlet has been attached: {}", this, swaggerServlet.dump());
162 * Retrieves cached server based on servlet path.
164 * @param servletPath servlet path
165 * @return the jetty servlet holder
167 * @throws IllegalArgumentException if invalid arguments are provided
169 protected synchronized ServletHolder getJerseyServlet(String servletPath) {
171 return jerseyServlets.computeIfAbsent(servletPath, key -> {
173 ServletHolder jerseyServlet =
174 context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, servletPath);
175 jerseyServlet.setInitOrder(0);
177 return jerseyServlet;
182 * Retrieves cached default servlet based on servlet path.
184 * @param servletPath servlet path
185 * @return the jetty servlet holder
187 * @throws IllegalArgumentException if invalid arguments are provided
189 protected synchronized ServletHolder getDefaultServlet(String servPath) {
191 return defaultServlets.computeIfAbsent(servPath, key -> context.addServlet(DefaultServlet.class, servPath));
195 public synchronized void addServletPackage(String servletPath, String restPackage) {
196 String servPath = servletPath;
197 if (StringUtils.isBlank(restPackage)) {
198 throw new IllegalArgumentException("No discoverable REST package provided");
201 if (servPath == null || servPath.isEmpty()) {
205 ServletHolder jerseyServlet = this.getJerseyServlet(servPath);
207 initStandardParams(jerseyServlet);
209 String initPackages = jerseyServlet.getInitParameter(ServerProperties.PROVIDER_PACKAGES);
210 if (initPackages == null) {
211 initPackages = restPackage;
214 initPackages += "," + restPackage;
217 jerseyServlet.setInitParameter(ServerProperties.PROVIDER_PACKAGES, initPackages);
219 if (logger.isDebugEnabled()) {
220 logger.debug("{}: added REST package: {}", this, jerseyServlet.dump());
225 public synchronized void addServletClass(String servletPath, String restClass) {
227 if (StringUtils.isBlank(restClass)) {
228 throw new IllegalArgumentException("No discoverable REST class provided");
231 if (servletPath == null || servletPath.isEmpty()) {
235 ServletHolder jerseyServlet = this.getJerseyServlet(servletPath);
237 initStandardParams(jerseyServlet);
239 String initClasses = jerseyServlet.getInitParameter(ServerProperties.PROVIDER_CLASSNAMES);
240 if (initClasses == null) {
241 initClasses = restClass;
244 initClasses += "," + restClass;
247 jerseyServlet.setInitParameter(ServerProperties.PROVIDER_CLASSNAMES, initClasses);
249 if (logger.isDebugEnabled()) {
250 logger.debug("{}: added REST class: {}", this, jerseyServlet.dump());
255 public synchronized void addServletResource(String servletPath, String resoureBase) {
257 if (StringUtils.isBlank(resoureBase)) {
258 throw new IllegalArgumentException("No resourceBase provided");
261 if (servletPath == null || servletPath.isEmpty()) {
265 ServletHolder defaultServlet = this.getDefaultServlet(servletPath);
267 defaultServlet.setInitParameter(SERVLET_HOLDER_RESOURCE_BASE, resoureBase);
268 defaultServlet.setInitParameter(SERVLET_HOLDER_DIR_ALLOWED, "false");
269 defaultServlet.setInitParameter(SERVLET_HOLDER_PATH_INFO_ONLY, "true");
271 if (logger.isDebugEnabled()) {
272 logger.debug("{}: added REST class: {}", this, defaultServlet.dump());
277 * Adds "standard" parameters to the initParameter set. Sets swagger parameters, if specified, and sets the class
278 * provider property. This can be invoked multiple times, but only the first actually causes any changes to the
281 * @param jerseyServlet servlet into which parameters should be added
283 private void initStandardParams(ServletHolder jerseyServlet) {
284 String initClasses = jerseyServlet.getInitParameter(ServerProperties.PROVIDER_CLASSNAMES);
285 if (initClasses != null) {
289 initClasses = classProvider;
291 if (this.swaggerId != null) {
292 initClasses += "," + SWAGGER_INIT_CLASSNAMES_PARAM_VALUE;
294 jerseyServlet.setInitParameter(SWAGGER_CONTEXT_ID, swaggerId);
295 jerseyServlet.setInitParameter(SWAGGER_SCANNER_ID, swaggerId);
298 jerseyServlet.setInitParameter(ServerProperties.PROVIDER_CLASSNAMES, initClasses);
300 jerseyServlet.setInitParameter(ServerProperties.METAINF_SERVICES_LOOKUP_DISABLE, "true");
304 * Note: this must be invoked <i>before</i> {@link #addServletClass(String, String)} or
305 * {@link #addServletPackage(String, String)}.
308 public void setSerializationProvider(String provider) {
309 classProvider = provider;
313 public String toString() {
314 StringBuilder builder = new StringBuilder();
315 builder.append("JettyJerseyServer [Jerseyservlets=").append(jerseyServlets).append(", Defaultservlets=")
316 .append(defaultServlets).append(", swaggerId=").append(swaggerId).append(", toString()=")
317 .append(super.toString()).append("]");
318 return builder.toString();