aboutsummaryrefslogtreecommitdiffstats
path: root/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/Main.java
blob: 3269c8436470bac65529c18983770f089e6f3a8c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
/*******************************************************************************
 * ============LICENSE_START==================================================
 * * org.onap.dmaap
 * * ===========================================================================
 * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
 * * ===========================================================================
 * * Licensed under the Apache License, Version 2.0 (the "License");
 * * you may not use this file except in compliance with the License.
 * * You may obtain a copy of the License at
 * *
 *  *      http://www.apache.org/licenses/LICENSE-2.0
 * *
 *  * Unless required by applicable law or agreed to in writing, software
 * * distributed under the License is distributed on an "AS IS" BASIS,
 * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * * See the License for the specific language governing permissions and
 * * limitations under the License.
 * * ============LICENSE_END====================================================
 * *
 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
 * *
 ******************************************************************************/


package org.onap.dmaap.datarouter.provisioning;

import static java.lang.System.exit;

import com.att.eelf.configuration.EELFLogger;
import com.att.eelf.configuration.EELFManager;
import java.io.File;
import java.io.IOException;
import java.security.Security;
import java.util.EnumSet;
import java.util.Properties;
import java.util.Timer;
import javax.servlet.DispatcherType;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.NCSARequestLog;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.onap.dmaap.datarouter.provisioning.utils.AafPropsUtils;
import org.onap.dmaap.datarouter.provisioning.utils.DB;
import org.onap.dmaap.datarouter.provisioning.utils.DRProvCadiFilter;
import org.onap.dmaap.datarouter.provisioning.utils.LogfileLoader;
import org.onap.dmaap.datarouter.provisioning.utils.PurgeLogDirTask;
import org.onap.dmaap.datarouter.provisioning.utils.ThrottleFilter;

/**
 * <p>
 * A main class which may be used to start the provisioning server with an "embedded" Jetty server. Configuration is
 * done via the properties file <i>provserver.properties</i>, which should be in the CLASSPATH. The provisioning server
 * may also be packaged with a web.xml and started as a traditional webapp.
 * </p>
 * <p>
 * Most of the work of the provisioning server is carried out within the eight servlets (configured below) that are used
 * to handle each of the eight types of requests the server may receive. In addition, there are background threads
 * started to perform other tasks:
 * </p>
 * <ul>
 * <li>One background Thread runs the {@link LogfileLoader} in order to process incoming logfiles.
 * This Thread is created as a side effect of the first successful POST to the /internal/logs/ servlet.</li>
 * <li>One background Thread runs the {@link SynchronizerTask} which is used to periodically
 * synchronize the database between active and standby servers.</li>
 * <li>One background Thread runs the {@link Poker} which is used to notify the nodes whenever
 * provisioning data changes.</li>
 * <li>One task is run once a day to run {@link PurgeLogDirTask} which purges older logs from the
 * /opt/app/datartr/logs directory.</li>
 * </ul>
 * <p>
 * The provisioning server is stopped by issuing a GET to the URL http://127.0.0.1/internal/halt using <i>curl</i> or
 * some other such tool.
 * </p>
 *
 * @author Robert Eby
 * @version $Id: Main.java,v 1.12 2014/03/12 19:45:41 eby Exp $
 */
public class Main {

    public static final EELFLogger intlogger = EELFManager.getInstance()
                                                       .getLogger("org.onap.dmaap.datarouter.provisioning.internal");

    /**
     * The one and only {@link Server} instance in this JVM.
     */
    private static Server server;
    static AafPropsUtils aafPropsUtils;

    /**
     * Starts the Data Router Provisioning server.
     *
     * @param args not used
     * @throws Exception if Jetty has a problem starting
     */
    public static void main(String[] args) throws Exception {
        Security.setProperty("networkaddress.cache.ttl", "4");
        // Check DB is accessible and contains the expected tables
        if (!checkDatabase()) {
            intlogger.error("Data Router Provisioning database init failure. Exiting.");
            exit(1);
        }

        intlogger.info("PROV0000 **** Data Router Provisioning Server starting....");

        Security.setProperty("networkaddress.cache.ttl", "4");
        Properties provProperties = (new DB()).getProperties();
        int httpPort = Integer.parseInt(provProperties
                                             .getProperty("org.onap.dmaap.datarouter.provserver.http.port", "8080"));
        final int httpsPort = Integer.parseInt(provProperties
                                             .getProperty("org.onap.dmaap.datarouter.provserver.https.port", "8443"));

        // Server's thread pool
        QueuedThreadPool queuedThreadPool = new QueuedThreadPool();
        queuedThreadPool.setMinThreads(10);
        queuedThreadPool.setMaxThreads(200);
        queuedThreadPool.setDetailedDump(false);

        // The server itself
        server = new Server(queuedThreadPool);
        server.setStopAtShutdown(true);
        server.setStopTimeout(5000);
        server.setDumpAfterStart(false);
        server.setDumpBeforeStop(false);

        // Request log configuration
        NCSARequestLog ncsaRequestLog = new NCSARequestLog();
        ncsaRequestLog.setFilename(provProperties
                                           .getProperty("org.onap.dmaap.datarouter.provserver.accesslog.dir")
                                           + "/request.log.yyyy_mm_dd");
        ncsaRequestLog.setFilenameDateFormat("yyyyMMdd");
        ncsaRequestLog.setRetainDays(90);
        ncsaRequestLog.setAppend(true);
        ncsaRequestLog.setExtended(false);
        ncsaRequestLog.setLogCookies(false);
        ncsaRequestLog.setLogTimeZone("GMT");

        RequestLogHandler requestLogHandler = new RequestLogHandler();
        requestLogHandler.setRequestLog(ncsaRequestLog);
        server.setRequestLog(ncsaRequestLog);

        // HTTP configuration
        HttpConfiguration httpConfiguration = new HttpConfiguration();
        httpConfiguration.setSecureScheme("https");
        httpConfiguration.setSecurePort(httpsPort);
        httpConfiguration.setOutputBufferSize(32768);
        httpConfiguration.setRequestHeaderSize(8192);
        httpConfiguration.setResponseHeaderSize(8192);
        httpConfiguration.setSendServerVersion(true);
        httpConfiguration.setSendDateHeader(false);

        try {
            AafPropsUtils.init(new File(provProperties.getProperty(
                "org.onap.dmaap.datarouter.provserver.aafprops.path",
                "/opt/app/osaaf/local/org.onap.dmaap-dr.props")));
        } catch (IOException e) {
            intlogger.error("NODE0314 Failed to load AAF props. Exiting", e);
            exit(1);
        }
        aafPropsUtils = AafPropsUtils.getInstance();

        //HTTP Connector
        HandlerCollection handlerCollection;
        try (ServerConnector httpServerConnector =
                     new ServerConnector(server, new HttpConnectionFactory(httpConfiguration))) {
            httpServerConnector.setPort(httpPort);
            httpServerConnector.setAcceptQueueSize(2);
            httpServerConnector.setIdleTimeout(300000);

            // SSL Context
            SslContextFactory sslContextFactory = new SslContextFactory();
            sslContextFactory.setKeyStoreType(AafPropsUtils.KEYSTORE_TYPE_PROPERTY);
            sslContextFactory.setKeyStorePath(aafPropsUtils.getKeystorePathProperty());
            sslContextFactory.setKeyStorePassword(aafPropsUtils.getKeystorePassProperty());
            sslContextFactory.setKeyManagerPassword(aafPropsUtils.getKeystorePassProperty());

            String truststorePathProperty = aafPropsUtils.getTruststorePathProperty();
            if (truststorePathProperty != null && truststorePathProperty.length() > 0) {
                intlogger.info("@@ TS -> " + truststorePathProperty);
                sslContextFactory.setTrustStoreType(AafPropsUtils.TRUESTSTORE_TYPE_PROPERTY);
                sslContextFactory.setTrustStorePath(truststorePathProperty);
                sslContextFactory.setTrustStorePassword(aafPropsUtils.getTruststorePassProperty());
            } else {
                sslContextFactory.setTrustStorePath(AafPropsUtils.DEFAULT_TRUSTSTORE);
                sslContextFactory.setTrustStorePassword("changeit");
            }

            sslContextFactory.setWantClientAuth(true);
            sslContextFactory.setExcludeCipherSuites(
                    "SSL_RSA_WITH_DES_CBC_SHA",
                    "SSL_DHE_RSA_WITH_DES_CBC_SHA",
                    "SSL_DHE_DSS_WITH_DES_CBC_SHA",
                    "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
                    "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
                    "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
                    "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"
            );
            sslContextFactory.addExcludeProtocols("SSLv3");
            sslContextFactory.setIncludeProtocols(provProperties.getProperty(
                    "org.onap.dmaap.datarouter.provserver.https.include.protocols",
                    "TLSv1.1|TLSv1.2").trim().split("\\|"));

            intlogger.info("Not supported protocols prov server:-"
                                   + String.join(",", sslContextFactory.getExcludeProtocols()));
            intlogger.info("Supported protocols prov server:-"
                                   + String.join(",", sslContextFactory.getIncludeProtocols()));
            intlogger.info("Not supported ciphers prov server:-"
                                   + String.join(",", sslContextFactory.getExcludeCipherSuites()));
            intlogger.info("Supported ciphers prov server:-"
                                   + String.join(",", sslContextFactory.getIncludeCipherSuites()));

            // HTTPS configuration
            HttpConfiguration httpsConfiguration = new HttpConfiguration(httpConfiguration);
            httpsConfiguration.setRequestHeaderSize(8192);

            // HTTPS connector
            try (ServerConnector httpsServerConnector = new ServerConnector(server,
                    new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
                    new HttpConnectionFactory(httpsConfiguration))) {

                httpsServerConnector.setPort(httpsPort);
                httpsServerConnector.setIdleTimeout(30000);
                httpsServerConnector.setAcceptQueueSize(2);

                // Servlet and Filter configuration
                ServletContextHandler servletContextHandler = new ServletContextHandler(0);
                servletContextHandler.setContextPath("/");
                servletContextHandler.addServlet(new ServletHolder(new FeedServlet()), "/feed/*");
                servletContextHandler.addServlet(new ServletHolder(new FeedLogServlet()), "/feedlog/*");
                servletContextHandler.addServlet(new ServletHolder(new PublishServlet()), "/publish/*");
                servletContextHandler.addServlet(new ServletHolder(new SubscribeServlet()), "/subscribe/*");
                servletContextHandler.addServlet(new ServletHolder(new StatisticsServlet()), "/statistics/*");
                servletContextHandler.addServlet(new ServletHolder(new SubLogServlet()), "/sublog/*");
                servletContextHandler.addServlet(new ServletHolder(new GroupServlet()), "/group/*");
                servletContextHandler.addServlet(new ServletHolder(new SubscriptionServlet()), "/subs/*");
                servletContextHandler.addServlet(new ServletHolder(new InternalServlet()), "/internal/*");
                servletContextHandler.addServlet(new ServletHolder(new RouteServlet()), "/internal/route/*");
                servletContextHandler.addServlet(new ServletHolder(new DRFeedsServlet()), "/");
                servletContextHandler.addFilter(new FilterHolder(new ThrottleFilter()),
                        "/publish/*", EnumSet.of(DispatcherType.REQUEST));

                //CADI Filter activation check
                if (Boolean.parseBoolean(provProperties.getProperty(
                        "org.onap.dmaap.datarouter.provserver.cadi.enabled", "false"))) {
                    servletContextHandler.addFilter(new FilterHolder(new DRProvCadiFilter(true, aafPropsUtils.getPropAccess())),
                            "/*", EnumSet.of(DispatcherType.REQUEST));
                    intlogger.info("PROV0001 AAF CADI Auth enabled for ");
                }

                ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection();
                contextHandlerCollection.addHandler(servletContextHandler);

                // Server's Handler collection
                handlerCollection = new HandlerCollection();
                handlerCollection.setHandlers(new Handler[]{contextHandlerCollection, new DefaultHandler()});
                handlerCollection.addHandler(requestLogHandler);

                server.setConnectors(new Connector[]{httpServerConnector, httpsServerConnector});
            }
        }
        server.setHandler(handlerCollection);

        // Daemon to clean up the log directory on a daily basis
        Timer rolex = new Timer();
        rolex.scheduleAtFixedRate(new PurgeLogDirTask(), 0, 86400000L);    // run once per day

        // Start LogfileLoader
        LogfileLoader.getLoader();

        try {
            server.start();
            intlogger.info("Prov Server started-" + server.getState());
        } catch (Exception e) {
            intlogger.error("Jetty failed to start. Exiting: " + e.getMessage(), e);
            exit(1);
        }
        server.join();
        intlogger.info("PROV0001 **** AT&T Data Router Provisioning Server halted.");
    }

    private static boolean checkDatabase() {
        DB db = new DB();
        return db.runRetroFits();
    }

    /**
     * Stop the Jetty server.
     */
    static void shutdown() {
        new Thread(() -> {
            try {
                server.stop();
                Thread.sleep(5000L);
                exit(0);
            } catch (Exception e) {
                intlogger.error("Exception in Main.shutdown(): " + e.getMessage(), e);
            }
        });
    }
}