9932d094fbf1740cba2140ca294e007228699fce
[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 java.util.HashMap;
24
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 import io.swagger.jersey.config.JerseyJaxrsConfig;
31
32 /**
33  * REST Jetty Server that uses Jersey Servlets to support JAX-RS Web Services
34  */
35 public class JettyJerseyServer extends JettyServletServer {
36
37     /**
38      * Swagger API Base Path
39      */
40     protected static final String SWAGGER_API_BASEPATH = "swagger.api.basepath";
41
42     /**
43      * Swagger Context ID
44      */
45     protected static final String SWAGGER_CONTEXT_ID = "swagger.context.id";
46
47     /**
48      * Swagger Scanner ID
49      */
50     protected static final String SWAGGER_SCANNER_ID = "swagger.scanner.id";
51
52     /**
53      * Swagger Pretty Print
54      */
55     protected static final String SWAGGER_PRETTY_PRINT = "swagger.pretty.print";
56
57     /**
58      * Swagger Packages
59      */
60     protected static final String SWAGGER_INIT_PACKAGES_PARAM_VALUE = "io.swagger.jaxrs.listing";
61
62     /**
63      * Jersey Packages Init Param Name
64      */
65     protected static final String JERSEY_INIT_PACKAGES_PARAM_NAME = "jersey.config.server.provider.packages";
66
67     /**
68      * Jersey Packages Init Param Value
69      */
70     protected static final String JERSEY_INIT_PACKAGES_PARAM_VALUE = "com.fasterxml.jackson.jaxrs.json";
71
72     /**
73      * Jersey Classes Init Param Name
74      */
75     protected static final String JERSEY_INIT_CLASSNAMES_PARAM_NAME = "jersey.config.server.provider.classnames";
76
77     /**
78      * Jersey Jackson Classes Init Param Value
79      */
80     protected static final String JERSEY_JACKSON_INIT_CLASSNAMES_PARAM_VALUE =
81             "com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider";
82
83     /**
84      * Jersey Swagger Classes Init Param Value
85      */
86     protected static final String SWAGGER_INIT_CLASSNAMES_PARAM_VALUE =
87             "io.swagger.jaxrs.listing.ApiListingResource," + "io.swagger.jaxrs.listing.SwaggerSerializers";
88     /**
89      * Logger
90      */
91     protected static Logger logger = LoggerFactory.getLogger(JettyJerseyServer.class);
92
93     /**
94      * Container for servlets
95      */
96     protected HashMap<String, ServletHolder> servlets = new HashMap<>();
97
98     /**
99      * Swagger ID
100      */
101     protected String swaggerId = null;
102
103     /**
104      * Constructor
105      * 
106      * @param name name
107      * @param https enable https?
108      * @param host host server host
109      * @param port port server port
110      * @param swagger support swagger?
111      * @param contextPath context path
112      * 
113      * @throws IllegalArgumentException in invalid arguments are provided
114      */
115     public JettyJerseyServer(String name, boolean https, String host, int port, String contextPath, boolean swagger) {
116
117         super(name, https, host, port, contextPath);
118         if (swagger) {
119             this.swaggerId = "swagger-" + this.port;
120             attachSwaggerServlet(https);
121         }
122     }
123
124     /**
125      * attaches a swagger initialization servlet
126      */
127     protected void attachSwaggerServlet(boolean https) {
128
129         ServletHolder swaggerServlet = context.addServlet(JerseyJaxrsConfig.class, "/");
130
131         String hostname = this.connector.getHost();
132         if (hostname == null || hostname.isEmpty() || hostname.equals(NetworkUtil.IPv4_WILDCARD_ADDRESS)) {
133             hostname = NetworkUtil.getHostname();
134         }
135
136         swaggerServlet.setInitParameter(SWAGGER_API_BASEPATH,
137                 ((https) ? "https://" : "http://") + hostname + ":" + this.connector.getPort() + "/");
138         swaggerServlet.setInitParameter(SWAGGER_CONTEXT_ID, swaggerId);
139         swaggerServlet.setInitParameter(SWAGGER_SCANNER_ID, swaggerId);
140         swaggerServlet.setInitParameter(SWAGGER_PRETTY_PRINT, "true");
141         swaggerServlet.setInitOrder(2);
142
143         if (logger.isDebugEnabled()) {
144             logger.debug("{}: Swagger Servlet has been attached: {}", this, swaggerServlet.dump());
145         }
146     }
147
148     /**
149      * retrieves cached server based on servlet path
150      * 
151      * @param servletPath servlet path
152      * @return the jetty servlet holder
153      * 
154      * @throws IllegalArgumentException if invalid arguments are provided
155      */
156     protected synchronized ServletHolder getServlet(String servletPath) {
157
158         ServletHolder jerseyServlet = servlets.get(servletPath);
159         if (jerseyServlet == null) {
160             jerseyServlet = context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, servletPath);
161             jerseyServlet.setInitOrder(0);
162             servlets.put(servletPath, jerseyServlet);
163         }
164
165         return jerseyServlet;
166     }
167
168     @Override
169     public synchronized void addServletPackage(String servletPath, String restPackage) {
170         String servPath = servletPath;
171         if (restPackage == null || restPackage.isEmpty()) {
172             throw new IllegalArgumentException("No discoverable REST package provided");
173         }
174
175         if (servPath == null || servPath.isEmpty()) {
176             servPath = "/*";
177         }
178
179         ServletHolder jerseyServlet = this.getServlet(servPath);
180
181         String initClasses = jerseyServlet.getInitParameter(JERSEY_INIT_CLASSNAMES_PARAM_NAME);
182         if (initClasses != null && !initClasses.isEmpty()) {
183             logger.warn("Both packages and classes are used in Jetty+Jersey Configuration: {}", restPackage);
184         }
185
186         String initPackages = jerseyServlet.getInitParameter(JERSEY_INIT_PACKAGES_PARAM_NAME);
187         if (initPackages == null) {
188             if (this.swaggerId != null) {
189                 initPackages =
190                         JERSEY_INIT_PACKAGES_PARAM_VALUE + "," + SWAGGER_INIT_PACKAGES_PARAM_VALUE + "," + restPackage;
191
192                 jerseyServlet.setInitParameter(SWAGGER_CONTEXT_ID, swaggerId);
193                 jerseyServlet.setInitParameter(SWAGGER_SCANNER_ID, swaggerId);
194             } else {
195                 initPackages = JERSEY_INIT_PACKAGES_PARAM_VALUE + "," + restPackage;
196             }
197         } else {
198             initPackages = initPackages + "," + restPackage;
199         }
200
201         jerseyServlet.setInitParameter(JERSEY_INIT_PACKAGES_PARAM_NAME, initPackages);
202
203         if (logger.isDebugEnabled()) {
204             logger.debug("{}: added REST package: {}", this, jerseyServlet.dump());
205         }
206     }
207
208     @Override
209     public synchronized void addServletClass(String servletPath, String restClass) {
210
211         if (restClass == null || restClass.isEmpty()) {
212             throw new IllegalArgumentException("No discoverable REST class provided");
213         }
214
215         if (servletPath == null || servletPath.isEmpty()) {
216             servletPath = "/*";
217         }
218
219         ServletHolder jerseyServlet = this.getServlet(servletPath);
220
221         String initPackages = jerseyServlet.getInitParameter(JERSEY_INIT_PACKAGES_PARAM_NAME);
222         if (initPackages != null && !initPackages.isEmpty()) {
223             logger.warn("Both classes and packages are used in Jetty+Jersey Configuration: {}", restClass);
224         }
225
226         String initClasses = jerseyServlet.getInitParameter(JERSEY_INIT_CLASSNAMES_PARAM_NAME);
227         if (initClasses == null) {
228             if (this.swaggerId != null) {
229                 initClasses = JERSEY_JACKSON_INIT_CLASSNAMES_PARAM_VALUE + "," + SWAGGER_INIT_CLASSNAMES_PARAM_VALUE
230                         + "," + restClass;
231
232                 jerseyServlet.setInitParameter(SWAGGER_CONTEXT_ID, swaggerId);
233                 jerseyServlet.setInitParameter(SWAGGER_SCANNER_ID, swaggerId);
234             } else {
235                 initClasses = JERSEY_JACKSON_INIT_CLASSNAMES_PARAM_VALUE + "," + restClass;
236             }
237         } else {
238             initClasses = initClasses + "," + restClass;
239         }
240
241         jerseyServlet.setInitParameter(JERSEY_INIT_CLASSNAMES_PARAM_NAME, initClasses);
242
243         if (logger.isDebugEnabled()) {
244             logger.debug("{}: added REST class: {}", this, jerseyServlet.dump());
245         }
246     }
247
248     @Override
249     public String toString() {
250         StringBuilder builder = new StringBuilder();
251         builder.append("JettyJerseyServer [servlets=").append(servlets).append(", swaggerId=").append(swaggerId)
252                 .append(", toString()=").append(super.toString()).append("]");
253         return builder.toString();
254     }
255 }