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