Checkstyle fixes for datarouter prov
[dmaap/datarouter.git] / datarouter-prov / src / main / java / org / onap / dmaap / datarouter / provisioning / Main.java
1 /*******************************************************************************
2  * ============LICENSE_START==================================================
3  * * org.onap.dmaap
4  * * ===========================================================================
5  * * Copyright © 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  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
21  * *
22  ******************************************************************************/
23
24
25 package org.onap.dmaap.datarouter.provisioning;
26
27 import com.att.eelf.configuration.EELFLogger;
28 import com.att.eelf.configuration.EELFManager;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.security.Security;
32 import java.util.EnumSet;
33 import java.util.Properties;
34 import java.util.Timer;
35 import javax.servlet.DispatcherType;
36 import org.eclipse.jetty.http.HttpVersion;
37 import org.eclipse.jetty.server.Connector;
38 import org.eclipse.jetty.server.Handler;
39 import org.eclipse.jetty.server.HttpConfiguration;
40 import org.eclipse.jetty.server.HttpConnectionFactory;
41 import org.eclipse.jetty.server.NCSARequestLog;
42 import org.eclipse.jetty.server.Server;
43 import org.eclipse.jetty.server.ServerConnector;
44 import org.eclipse.jetty.server.SslConnectionFactory;
45 import org.eclipse.jetty.server.handler.ContextHandlerCollection;
46 import org.eclipse.jetty.server.handler.DefaultHandler;
47 import org.eclipse.jetty.server.handler.HandlerCollection;
48 import org.eclipse.jetty.server.handler.RequestLogHandler;
49 import org.eclipse.jetty.servlet.FilterHolder;
50 import org.eclipse.jetty.servlet.ServletContextHandler;
51 import org.eclipse.jetty.servlet.ServletHolder;
52 import org.eclipse.jetty.util.ssl.SslContextFactory;
53 import org.eclipse.jetty.util.thread.QueuedThreadPool;
54 import org.onap.aaf.cadi.PropAccess;
55
56 import org.onap.dmaap.datarouter.provisioning.utils.DB;
57 import org.onap.dmaap.datarouter.provisioning.utils.DRProvCadiFilter;
58 import org.onap.dmaap.datarouter.provisioning.utils.LogfileLoader;
59 import org.onap.dmaap.datarouter.provisioning.utils.PurgeLogDirTask;
60 import org.onap.dmaap.datarouter.provisioning.utils.ThrottleFilter;
61
62 /**
63  * <p>
64  * A main class which may be used to start the provisioning server with an "embedded" Jetty server. Configuration is
65  * done via the properties file <i>provserver.properties</i>, which should be in the CLASSPATH. The provisioning server
66  * may also be packaged with a web.xml and started as a traditional webapp.
67  * </p>
68  * <p>
69  * Most of the work of the provisioning server is carried out within the eight servlets (configured below) that are used
70  * to handle each of the eight types of requests the server may receive. In addition, there are background threads
71  * started to perform other tasks:
72  * </p>
73  * <ul>
74  * <li>One background Thread runs the {@link LogfileLoader} in order to process incoming logfiles.
75  * This Thread is created as a side effect of the first successful POST to the /internal/logs/ servlet.</li>
76  * <li>One background Thread runs the {@link SynchronizerTask} which is used to periodically
77  * synchronize the database between active and standby servers.</li>
78  * <li>One background Thread runs the {@link Poker} which is used to notify the nodes whenever
79  * provisioning data changes.</li>
80  * <li>One task is run once a day to run {@link PurgeLogDirTask} which purges older logs from the
81  * /opt/app/datartr/logs directory.</li>
82  * </ul>
83  * <p>
84  * The provisioning server is stopped by issuing a GET to the URL http://127.0.0.1/internal/halt using <i>curl</i> or
85  * some other such tool.
86  * </p>
87  *
88  * @author Robert Eby
89  * @version $Id: Main.java,v 1.12 2014/03/12 19:45:41 eby Exp $
90  */
91 public class Main {
92
93     /**
94      * The truststore to use if none is specified.
95      */
96     static final String DEFAULT_TRUSTSTORE = "/opt/java/jdk/jdk180/jre/lib/security/cacerts";
97     static final String KEYSTORE_TYPE_PROPERTY = "org.onap.dmaap.datarouter.provserver.keystore.type";
98     static final String KEYSTORE_PATH_PROPERTY = "org.onap.dmaap.datarouter.provserver.keystore.path";
99     static final String KEYSTORE_PASS_PROPERTY = "org.onap.dmaap.datarouter.provserver.keystore.password";
100     static final String TRUSTSTORE_PATH_PROPERTY = "org.onap.dmaap.datarouter.provserver.truststore.path";
101     static final String TRUSTSTORE_PASS_PROPERTY = "org.onap.dmaap.datarouter.provserver.truststore.password";
102     public static final EELFLogger intlogger = EELFManager.getInstance()
103                                                        .getLogger("org.onap.dmaap.datarouter.provisioning.internal");
104
105     /**
106      * The one and only {@link Server} instance in this JVM.
107      */
108     private static Server server;
109
110     class Inner {
111         InputStream getCadiProps() {
112             InputStream in = null;
113             try {
114                 in = getClass().getClassLoader().getResourceAsStream("drProvCadi.properties");
115             } catch (Exception e) {
116                 intlogger.error("Exception in Main.getCadiProps(): " + e.getMessage(), e);
117             }
118             return in;
119         }
120     }
121
122     /**
123      * Starts the Data Router Provisioning server.
124      *
125      * @param args not used
126      * @throws Exception if Jetty has a problem starting
127      */
128     public static void main(String[] args) throws Exception {
129         Security.setProperty("networkaddress.cache.ttl", "4");
130         // Check DB is accessible and contains the expected tables
131         if (!checkDatabase()) {
132             System.exit(1);
133         }
134
135         intlogger.info("PROV0000 **** AT&T Data Router Provisioning Server starting....");
136
137         Security.setProperty("networkaddress.cache.ttl", "4");
138         Properties provProperties = (new DB()).getProperties();
139         int httpPort = Integer.parseInt(provProperties
140                                              .getProperty("org.onap.dmaap.datarouter.provserver.http.port", "8080"));
141         final int httpsPort = Integer.parseInt(provProperties
142                                              .getProperty("org.onap.dmaap.datarouter.provserver.https.port", "8443"));
143
144         // Server's thread pool
145         QueuedThreadPool queuedThreadPool = new QueuedThreadPool();
146         queuedThreadPool.setMinThreads(10);
147         queuedThreadPool.setMaxThreads(200);
148         queuedThreadPool.setDetailedDump(false);
149
150         // The server itself
151         server = new Server(queuedThreadPool);
152         server.setStopAtShutdown(true);
153         server.setStopTimeout(5000);
154         server.setDumpAfterStart(false);
155         server.setDumpBeforeStop(false);
156
157         // Request log configuration
158         NCSARequestLog ncsaRequestLog = new NCSARequestLog();
159         ncsaRequestLog.setFilename(provProperties
160                                            .getProperty("org.onap.dmaap.datarouter.provserver.accesslog.dir")
161                                            + "/request.log.yyyy_mm_dd");
162         ncsaRequestLog.setFilenameDateFormat("yyyyMMdd");
163         ncsaRequestLog.setRetainDays(90);
164         ncsaRequestLog.setAppend(true);
165         ncsaRequestLog.setExtended(false);
166         ncsaRequestLog.setLogCookies(false);
167         ncsaRequestLog.setLogTimeZone("GMT");
168
169         RequestLogHandler requestLogHandler = new RequestLogHandler();
170         requestLogHandler.setRequestLog(ncsaRequestLog);
171         server.setRequestLog(ncsaRequestLog);
172
173         // HTTP configuration
174         HttpConfiguration httpConfiguration = new HttpConfiguration();
175         httpConfiguration.setSecureScheme("https");
176         httpConfiguration.setSecurePort(httpsPort);
177         httpConfiguration.setOutputBufferSize(32768);
178         httpConfiguration.setRequestHeaderSize(8192);
179         httpConfiguration.setResponseHeaderSize(8192);
180         httpConfiguration.setSendServerVersion(true);
181         httpConfiguration.setSendDateHeader(false);
182
183         //HTTP Connector
184         HandlerCollection handlerCollection;
185         try (ServerConnector httpServerConnector =
186                      new ServerConnector(server, new HttpConnectionFactory(httpConfiguration))) {
187             httpServerConnector.setPort(httpPort);
188             httpServerConnector.setAcceptQueueSize(2);
189             httpServerConnector.setIdleTimeout(300000);
190
191             // SSL Context
192             SslContextFactory sslContextFactory = new SslContextFactory();
193             sslContextFactory.setKeyStoreType(provProperties.getProperty(KEYSTORE_TYPE_PROPERTY, "jks"));
194             sslContextFactory.setKeyStorePath(provProperties.getProperty(KEYSTORE_PATH_PROPERTY));
195             sslContextFactory.setKeyStorePassword(provProperties.getProperty(KEYSTORE_PASS_PROPERTY));
196             sslContextFactory.setKeyManagerPassword(provProperties
197                                           .getProperty("org.onap.dmaap.datarouter.provserver.keymanager.password"));
198
199             String ts = provProperties.getProperty(TRUSTSTORE_PATH_PROPERTY);
200             if (ts != null && ts.length() > 0) {
201                 intlogger.info("@@ TS -> " + ts);
202                 sslContextFactory.setTrustStorePath(ts);
203                 sslContextFactory.setTrustStorePassword(provProperties.getProperty(TRUSTSTORE_PASS_PROPERTY));
204             } else {
205                 sslContextFactory.setTrustStorePath(DEFAULT_TRUSTSTORE);
206                 sslContextFactory.setTrustStorePassword("changeit");
207             }
208
209             sslContextFactory.setWantClientAuth(true);
210             sslContextFactory.setExcludeCipherSuites(
211                     "SSL_RSA_WITH_DES_CBC_SHA",
212                     "SSL_DHE_RSA_WITH_DES_CBC_SHA",
213                     "SSL_DHE_DSS_WITH_DES_CBC_SHA",
214                     "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
215                     "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
216                     "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
217                     "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"
218             );
219             sslContextFactory.addExcludeProtocols("SSLv3");
220             sslContextFactory.setIncludeProtocols(provProperties.getProperty(
221                     "org.onap.dmaap.datarouter.provserver.https.include.protocols",
222                     "TLSv1.1|TLSv1.2").trim().split("\\|"));
223
224             intlogger.info("Not supported protocols prov server:-"
225                                    + String.join(",", sslContextFactory.getExcludeProtocols()));
226             intlogger.info("Supported protocols prov server:-"
227                                    + String.join(",", sslContextFactory.getIncludeProtocols()));
228             intlogger.info("Not supported ciphers prov server:-"
229                                    + String.join(",", sslContextFactory.getExcludeCipherSuites()));
230             intlogger.info("Supported ciphers prov server:-"
231                                    + String.join(",", sslContextFactory.getIncludeCipherSuites()));
232
233             // HTTPS configuration
234             HttpConfiguration httpsConfiguration = new HttpConfiguration(httpConfiguration);
235             httpsConfiguration.setRequestHeaderSize(8192);
236
237             // HTTPS connector
238             try (ServerConnector httpsServerConnector = new ServerConnector(server,
239                     new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
240                     new HttpConnectionFactory(httpsConfiguration))) {
241
242                 httpsServerConnector.setPort(httpsPort);
243                 httpsServerConnector.setIdleTimeout(30000);
244                 httpsServerConnector.setAcceptQueueSize(2);
245
246                 // Servlet and Filter configuration
247                 ServletContextHandler servletContextHandler = new ServletContextHandler(0);
248                 servletContextHandler.setContextPath("/");
249                 servletContextHandler.addServlet(new ServletHolder(new FeedServlet()), "/feed/*");
250                 servletContextHandler.addServlet(new ServletHolder(new FeedLogServlet()), "/feedlog/*");
251                 servletContextHandler.addServlet(new ServletHolder(new PublishServlet()), "/publish/*");
252                 servletContextHandler.addServlet(new ServletHolder(new SubscribeServlet()), "/subscribe/*");
253                 servletContextHandler.addServlet(new ServletHolder(new StatisticsServlet()), "/statistics/*");
254                 servletContextHandler.addServlet(new ServletHolder(new SubLogServlet()), "/sublog/*");
255                 servletContextHandler.addServlet(new ServletHolder(new GroupServlet()), "/group/*");
256                 servletContextHandler.addServlet(new ServletHolder(new SubscriptionServlet()), "/subs/*");
257                 servletContextHandler.addServlet(new ServletHolder(new InternalServlet()), "/internal/*");
258                 servletContextHandler.addServlet(new ServletHolder(new RouteServlet()), "/internal/route/*");
259                 servletContextHandler.addServlet(new ServletHolder(new DRFeedsServlet()), "/");
260                 servletContextHandler.addFilter(new FilterHolder(new ThrottleFilter()),
261                         "/publish/*", EnumSet.of(DispatcherType.REQUEST));
262
263                 //CADI Filter activation check
264                 if (Boolean.parseBoolean(provProperties.getProperty(
265                         "org.onap.dmaap.datarouter.provserver.cadi.enabled", "false"))) {
266                     //Get cadi properties
267                     Properties cadiProperties = null;
268                     try {
269                         intlogger.info("PROV0001 Prov - Loading CADI properties");
270                         cadiProperties = new Properties();
271                         Inner obj = new Main().new Inner();
272                         InputStream in = obj.getCadiProps();
273                         cadiProperties.load(in);
274                     } catch (IOException ioe) {
275                         intlogger.error("PROV0001 Exception loading CADI properties: " + ioe.getMessage(), ioe);
276                     }
277                     cadiProperties.setProperty("aaf_locate_url", provProperties.getProperty("org.onap.dmaap.datarouter.provserver.cadi.aaf.url", "https://aaf-onap-test.osaaf.org:8095"));
278                     intlogger.info("PROV0001  aaf_url set to - " + cadiProperties.getProperty("aaf_url"));
279
280                     PropAccess access = new PropAccess(cadiProperties);
281                     servletContextHandler.addFilter(new FilterHolder(new DRProvCadiFilter(true, access)),
282                             "/*", EnumSet.of(DispatcherType.REQUEST));
283                 }
284
285                 ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection();
286                 contextHandlerCollection.addHandler(servletContextHandler);
287
288                 // Server's Handler collection
289                 handlerCollection = new HandlerCollection();
290                 handlerCollection.setHandlers(new Handler[]{contextHandlerCollection, new DefaultHandler()});
291                 handlerCollection.addHandler(requestLogHandler);
292
293                 server.setConnectors(new Connector[]{httpServerConnector, httpsServerConnector});
294             }
295         }
296         server.setHandler(handlerCollection);
297
298         // Daemon to clean up the log directory on a daily basis
299         Timer rolex = new Timer();
300         rolex.scheduleAtFixedRate(new PurgeLogDirTask(), 0, 86400000L);    // run once per day
301
302         // Start LogfileLoader
303         LogfileLoader.getLoader();
304
305         try {
306             server.start();
307             intlogger.info("Prov Server started-" + server.getState());
308         } catch (Exception e) {
309             intlogger.info("Jetty failed to start. Reporting will we unavailable: " + e.getMessage(), e);
310         }
311         server.join();
312         intlogger.info("PROV0001 **** AT&T Data Router Provisioning Server halted.");
313     }
314
315     private static boolean checkDatabase() {
316         DB db = new DB();
317         return db.runRetroFits();
318     }
319
320     /**
321      * Stop the Jetty server.
322      */
323     static void shutdown() {
324         new Thread(() -> {
325             try {
326                 server.stop();
327                 Thread.sleep(5000L);
328                 System.exit(0);
329             } catch (Exception e) {
330                 intlogger.error("Exception in Main.shutdown(): " + e.getMessage(), e);
331             }
332         });
333     }
334 }