a97a9bf58a8cba984cba451e3ebac2527b60f6dd
[policy/common.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * policy-endpoints
4  * ================================================================================
5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.common.endpoints.http.server.internal;
22
23 import io.swagger.jersey.config.JerseyJaxrsConfig;
24 import java.util.HashMap;
25 import org.eclipse.jetty.servlet.ServletHolder;
26 import org.onap.policy.common.utils.network.NetworkUtil;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * REST Jetty Server that uses Jersey Servlets to support JAX-RS Web Services.
32  */
33 public class JettyJerseyServer extends JettyServletServer {
34
35     /**
36      * Swagger API Base Path.
37      */
38     protected static final String SWAGGER_API_BASEPATH = "swagger.api.basepath";
39
40     /**
41      * Swagger Context ID.
42      */
43     protected static final String SWAGGER_CONTEXT_ID = "swagger.context.id";
44
45     /**
46      * Swagger Scanner ID.
47      */
48     protected static final String SWAGGER_SCANNER_ID = "swagger.scanner.id";
49
50     /**
51      * Swagger Pretty Print.
52      */
53     protected static final String SWAGGER_PRETTY_PRINT = "swagger.pretty.print";
54
55     /**
56      * Swagger Packages.
57      */
58     protected static final String SWAGGER_INIT_PACKAGES_PARAM_VALUE = "io.swagger.jaxrs.listing";
59
60     /**
61      * Jersey Packages Init Param Name.
62      */
63     protected static final String JERSEY_INIT_PACKAGES_PARAM_NAME = "jersey.config.server.provider.packages";
64
65     /**
66      * Jersey Packages Init Param Value.
67      */
68     protected static final String JERSEY_INIT_PACKAGES_PARAM_VALUE = "com.fasterxml.jackson.jaxrs.json";
69
70     /**
71      * Jersey Classes Init Param Name.
72      */
73     protected static final String JERSEY_INIT_CLASSNAMES_PARAM_NAME = "jersey.config.server.provider.classnames";
74
75     /**
76      * Jersey Jackson Classes Init Param Value.
77      */
78     protected static final String JERSEY_JACKSON_INIT_CLASSNAMES_PARAM_VALUE =
79             "com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider";
80
81     /**
82      * Jersey Swagger Classes Init Param Value.
83      */
84     protected static final String SWAGGER_INIT_CLASSNAMES_PARAM_VALUE =
85             "io.swagger.jaxrs.listing.ApiListingResource," + "io.swagger.jaxrs.listing.SwaggerSerializers";
86     /**
87      * Logger.
88      */
89     protected static Logger logger = LoggerFactory.getLogger(JettyJerseyServer.class);
90
91     /**
92      * Container for servlets.
93      */
94     protected HashMap<String, ServletHolder> servlets = new HashMap<>();
95
96     /**
97      * Swagger ID.
98      */
99     protected String swaggerId = null;
100
101     /**
102      * Constructor.
103      * 
104      * @param name name
105      * @param https enable https?
106      * @param host host server host
107      * @param port port server port
108      * @param swagger support swagger?
109      * @param contextPath context path
110      * 
111      * @throws IllegalArgumentException in invalid arguments are provided
112      */
113     public JettyJerseyServer(String name, boolean https, String host, int port, String contextPath, boolean swagger) {
114
115         super(name, https, host, port, contextPath);
116         if (swagger) {
117             this.swaggerId = "swagger-" + this.port;
118             attachSwaggerServlet(https);
119         }
120     }
121
122     /**
123      * Attaches a swagger initialization servlet.
124      */
125     protected void attachSwaggerServlet(boolean https) {
126
127         ServletHolder swaggerServlet = context.addServlet(JerseyJaxrsConfig.class, "/");
128
129         String hostname = this.connector.getHost();
130         if (hostname == null || hostname.isEmpty() || hostname.equals(NetworkUtil.IPv4_WILDCARD_ADDRESS)) {
131             hostname = NetworkUtil.getHostname();
132         }
133
134         swaggerServlet.setInitParameter(SWAGGER_API_BASEPATH,
135                 ((https) ? "https://" : "http://") + hostname + ":" + this.connector.getPort() + "/");
136         swaggerServlet.setInitParameter(SWAGGER_CONTEXT_ID, swaggerId);
137         swaggerServlet.setInitParameter(SWAGGER_SCANNER_ID, swaggerId);
138         swaggerServlet.setInitParameter(SWAGGER_PRETTY_PRINT, "true");
139         swaggerServlet.setInitOrder(2);
140
141         if (logger.isDebugEnabled()) {
142             logger.debug("{}: Swagger Servlet has been attached: {}", this, swaggerServlet.dump());
143         }
144     }
145
146     /**
147      * Retrieves cached server based on servlet path.
148      * 
149      * @param servletPath servlet path
150      * @return the jetty servlet holder
151      * 
152      * @throws IllegalArgumentException if invalid arguments are provided
153      */
154     protected synchronized ServletHolder getServlet(String servletPath) {
155
156         ServletHolder jerseyServlet = servlets.get(servletPath);
157         if (jerseyServlet == null) {
158             jerseyServlet = context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, servletPath);
159             jerseyServlet.setInitOrder(0);
160             servlets.put(servletPath, jerseyServlet);
161         }
162
163         return jerseyServlet;
164     }
165
166     @Override
167     public synchronized void addServletPackage(String servletPath, String restPackage) {
168         String servPath = servletPath;
169         if (restPackage == null || restPackage.isEmpty()) {
170             throw new IllegalArgumentException("No discoverable REST package provided");
171         }
172
173         if (servPath == null || servPath.isEmpty()) {
174             servPath = "/*";
175         }
176
177         ServletHolder jerseyServlet = this.getServlet(servPath);
178
179         String initClasses = jerseyServlet.getInitParameter(JERSEY_INIT_CLASSNAMES_PARAM_NAME);
180         if (initClasses != null && !initClasses.isEmpty()) {
181             logger.warn("Both packages and classes are used in Jetty+Jersey Configuration: {}", restPackage);
182         }
183
184         String initPackages = jerseyServlet.getInitParameter(JERSEY_INIT_PACKAGES_PARAM_NAME);
185         if (initPackages == null) {
186             if (this.swaggerId != null) {
187                 initPackages =
188                         JERSEY_INIT_PACKAGES_PARAM_VALUE + "," + SWAGGER_INIT_PACKAGES_PARAM_VALUE + "," + restPackage;
189
190                 jerseyServlet.setInitParameter(SWAGGER_CONTEXT_ID, swaggerId);
191                 jerseyServlet.setInitParameter(SWAGGER_SCANNER_ID, swaggerId);
192             } else {
193                 initPackages = JERSEY_INIT_PACKAGES_PARAM_VALUE + "," + restPackage;
194             }
195         } else {
196             initPackages = initPackages + "," + restPackage;
197         }
198
199         jerseyServlet.setInitParameter(JERSEY_INIT_PACKAGES_PARAM_NAME, initPackages);
200
201         if (logger.isDebugEnabled()) {
202             logger.debug("{}: added REST package: {}", this, jerseyServlet.dump());
203         }
204     }
205
206     @Override
207     public synchronized void addServletClass(String servletPath, String restClass) {
208
209         if (restClass == null || restClass.isEmpty()) {
210             throw new IllegalArgumentException("No discoverable REST class provided");
211         }
212
213         if (servletPath == null || servletPath.isEmpty()) {
214             servletPath = "/*";
215         }
216
217         ServletHolder jerseyServlet = this.getServlet(servletPath);
218
219         String initPackages = jerseyServlet.getInitParameter(JERSEY_INIT_PACKAGES_PARAM_NAME);
220         if (initPackages != null && !initPackages.isEmpty()) {
221             logger.warn("Both classes and packages are used in Jetty+Jersey Configuration: {}", restClass);
222         }
223
224         String initClasses = jerseyServlet.getInitParameter(JERSEY_INIT_CLASSNAMES_PARAM_NAME);
225         if (initClasses == null) {
226             if (this.swaggerId != null) {
227                 initClasses = JERSEY_JACKSON_INIT_CLASSNAMES_PARAM_VALUE + "," + SWAGGER_INIT_CLASSNAMES_PARAM_VALUE
228                         + "," + restClass;
229
230                 jerseyServlet.setInitParameter(SWAGGER_CONTEXT_ID, swaggerId);
231                 jerseyServlet.setInitParameter(SWAGGER_SCANNER_ID, swaggerId);
232             } else {
233                 initClasses = JERSEY_JACKSON_INIT_CLASSNAMES_PARAM_VALUE + "," + restClass;
234             }
235         } else {
236             initClasses = initClasses + "," + restClass;
237         }
238
239         jerseyServlet.setInitParameter(JERSEY_INIT_CLASSNAMES_PARAM_NAME, initClasses);
240
241         if (logger.isDebugEnabled()) {
242             logger.debug("{}: added REST class: {}", this, jerseyServlet.dump());
243         }
244     }
245
246     @Override
247     public String toString() {
248         StringBuilder builder = new StringBuilder();
249         builder.append("JettyJerseyServer [servlets=").append(servlets).append(", swaggerId=").append(swaggerId)
250                 .append(", toString()=").append(super.toString()).append("]");
251         return builder.toString();
252     }
253 }