datarouter-prov code clean - remove tabs
[dmaap/datarouter.git] / datarouter-prov / src / main / java / org / onap / dmaap / datarouter / provisioning / InternalServlet.java
index 14c960c..2719208 100644 (file)
-/*******************************************************************************\r
- * ============LICENSE_START==================================================\r
- * * org.onap.dmaap\r
- * * ===========================================================================\r
- * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
- * * ===========================================================================\r
- * * Licensed under the Apache License, Version 2.0 (the "License");\r
- * * you may not use this file except in compliance with the License.\r
- * * You may obtain a copy of the License at\r
- * * \r
- *  *      http://www.apache.org/licenses/LICENSE-2.0\r
- * * \r
- *  * Unless required by applicable law or agreed to in writing, software\r
- * * distributed under the License is distributed on an "AS IS" BASIS,\r
- * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * * See the License for the specific language governing permissions and\r
- * * limitations under the License.\r
- * * ============LICENSE_END====================================================\r
- * *\r
- * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
- * *\r
- ******************************************************************************/\r
-\r
-\r
-package org.onap.dmaap.datarouter.provisioning;\r
-\r
-import java.io.ByteArrayOutputStream;\r
-import java.io.File;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.nio.file.FileStore;\r
-import java.nio.file.FileSystem;\r
-import java.nio.file.Files;\r
-import java.nio.file.Path;\r
-import java.nio.file.Paths;\r
-import java.nio.file.StandardCopyOption;\r
-import java.util.Properties;\r
-\r
-import javax.servlet.http.HttpServletRequest;\r
-import javax.servlet.http.HttpServletResponse;\r
-\r
-import org.json.JSONArray;\r
-import org.onap.dmaap.datarouter.provisioning.beans.EventLogRecord;\r
-import org.onap.dmaap.datarouter.provisioning.beans.LogRecord;\r
-import org.onap.dmaap.datarouter.provisioning.beans.Parameters;\r
-import org.onap.dmaap.datarouter.provisioning.eelf.EelfMsgs;\r
-import org.onap.dmaap.datarouter.provisioning.utils.DB;\r
-import org.onap.dmaap.datarouter.provisioning.utils.LogfileLoader;\r
-import org.onap.dmaap.datarouter.provisioning.utils.RLEBitSet;\r
-\r
-import com.att.eelf.configuration.EELFLogger;\r
-import com.att.eelf.configuration.EELFManager;\r
-\r
-/**\r
- * <p>\r
- * This servlet handles requests to URLs under /internal on the provisioning server.\r
- * These include:\r
- * </p>\r
- * <div class="contentContainer">\r
- * <table class="packageSummary" border="0" cellpadding="3" cellspacing="0">\r
- * <caption><span>URL Path Summary</span><span class="tabEnd">&nbsp;</span></caption>\r
- * <tr>\r
- *   <th class="colFirst" width="15%">URL Path</th>\r
- *   <th class="colOne">Method</th>\r
- *   <th class="colLast">Purpose</th>\r
- * </tr>\r
- * <tr class="altColor">\r
- *   <td class="colFirst">/internal/prov</td>\r
- *   <td class="colOne">GET</td>\r
- *   <td class="colLast">used to GET a full JSON copy of the provisioning data.</td>\r
- * </tr>\r
- * <tr class="rowColor">\r
- *   <td class="colFirst">/internal/fetchProv</td>\r
- *   <td class="colOne">GET</td>\r
- *   <td class="colLast">used to signal to a standby POD that the provisioning data should be fetched from the active POD.</td>\r
- * </tr>\r
- * <tr class="altColor">\r
- *   <td class="colFirst" rowspan="2">/internal/logs</td>\r
- *   <td class="colOne">GET</td>\r
- *   <td class="colLast">used to GET an index of log files and individual logs for this provisioning server.</td>\r
- * </tr>\r
- * <tr class="altColor">\r
- *   <td class="colOne">POST</td>\r
- *   <td class="colLast">used to POST log files from the individual nodes to this provisioning server.</td>\r
- * </tr>\r
- * <tr class="rowColor">\r
- *   <td class="colFirst" rowspan="4">/internal/api</td>\r
- *   <td class="colOne">GET</td>\r
- *   <td class="colLast">used to GET an individual parameter value. The parameter name is specified by the path after /api/.</td>\r
- * </tr>\r
- * <tr class="rowColor">\r
- *   <td class="colOne">PUT</td>\r
- *   <td class="colLast">used to set an individual parameter value. The parameter name is specified by the path after /api/.</td>\r
- * </tr>\r
- * <tr class="rowColor">\r
- *   <td class="colOne">DELETE</td>\r
- *   <td class="colLast">used to remove an individual parameter value. The parameter name is specified by the path after /api/.</td>\r
- * </tr>\r
- * <tr class="rowColor">\r
- *   <td class="colOne">POST</td>\r
- *   <td class="colLast">used to create a new individual parameter value. The parameter name is specified by the path after /api/.</td>\r
- * </tr>\r
- * <tr class="altColor">\r
- *   <td class="colFirst">/internal/halt</td>\r
- *   <td class="colOne">GET</td>\r
- *   <td class="colLast">used to halt the server (must be accessed from 127.0.0.1).</td>\r
- * </tr>\r
- * <tr class="rowColor">\r
- *   <td class="colFirst" rowspan="2">/internal/drlogs</td>\r
- *   <td class="colOne">GET</td>\r
- *   <td class="colLast">used to get a list of DR log entries available for retrieval.\r
- *   Note: these are the actual data router log entries sent to the provisioning server\r
- *   by the nodes, not the provisioning server's internal logs (access via /internal/logs above).\r
- *   The range is returned as a list of record sequence numbers.</td>\r
- * </tr>\r
- * <tr class="rowColor">\r
- *   <td class="colOne">POST</td>\r
- *   <td class="colLast">used to retrieve specific log entries.\r
- *   The sequence numbers of the records to fetch are POST-ed; the records matching the sequence numbers are returned.</td>\r
- * </tr>\r
- * <tr class="altColor">\r
- *   <td class="colFirst">/internal/route/*</td>\r
- *   <td class="colOne">*</td>\r
- *   <td class="colLast">URLs under this path are handled via the {@link org.onap.dmaap.datarouter.provisioning.RouteServlet}</td>\r
- * </tr>\r
- * </table>\r
- * </div>\r
- * <p>\r
- * Authorization to use these URLs is a little different than for other URLs on the provisioning server.\r
- * For the most part, the IP address that the request comes from should be either:\r
- * </p>\r
- * <ol>\r
- * <li>an IP address of a provisioning server, or</li>\r
- * <li>the IP address of a node (to allow access to /internal/prov), or</li>\r
- * <li>an IP address from the "<i>special subnet</i>" which is configured with\r
- * the PROV_SPECIAL_SUBNET parameter.\r
- * </ol>\r
- * <p>\r
- * In addition, requests to /internal/halt can ONLY come from localhost (127.0.0.1) on the HTTP port.\r
- * </p>\r
- * <p>\r
- * All DELETE/GET/PUT/POST requests made to /internal/api on this servlet on the standby server are\r
- * proxied to the active server (using the {@link ProxyServlet}) if it is up and reachable.\r
- * </p>\r
- *\r
- * @author Robert Eby\r
- * @version $Id: InternalServlet.java,v 1.23 2014/03/24 18:47:10 eby Exp $\r
- */\r
-@SuppressWarnings("serial")\r
-public class InternalServlet extends ProxyServlet {\r
-       private static Integer logseq = new Integer(0); // another piece of info to make log spool file names unique\r
-       //Adding EELF Logger Rally:US664892 \r
-    private static EELFLogger eelflogger = EELFManager.getInstance().getLogger("org.onap.dmaap.datarouter.provisioning.InternalServlet");\r
-\r
-       /**\r
-        * Delete a parameter at the address /internal/api/&lt;parameter&gt;.\r
-        * See the <b>Internal API</b> document for details on how this method should be invoked.\r
-        */\r
-       @Override\r
-       public void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
-               setIpAndFqdnForEelf("doDelete");\r
-               eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_FEEDID, req.getHeader(BEHALF_HEADER),getIdFromPath(req)+"");\r
-               EventLogRecord elr = new EventLogRecord(req);\r
-               if (!isAuthorizedForInternal(req)) {\r
-                       elr.setMessage("Unauthorized.");\r
-                       elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
-                       eventlogger.info(elr);\r
-                       resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthorized.");\r
-                       return;\r
-               }\r
-\r
-               String path = req.getPathInfo();\r
-               if (path.startsWith("/api/")) {\r
-                       if (isProxyOK(req) && isProxyServer()) {\r
-                               super.doDelete(req, resp);\r
-                               return;\r
-                       }\r
-                       String key = path.substring(5);\r
-                       if (key.length() > 0) {\r
-                               Parameters param = Parameters.getParameter(key);\r
-                               if (param != null) {\r
-                                       if (doDelete(param)) {\r
-                                               elr.setResult(HttpServletResponse.SC_OK);\r
-                                               eventlogger.info(elr);\r
-                                               resp.setStatus(HttpServletResponse.SC_OK);\r
-                                               provisioningDataChanged();\r
-                                               provisioningParametersChanged();\r
-                                       } else {\r
-                                               // Something went wrong with the DELETE\r
-                                               elr.setResult(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\r
-                                               eventlogger.info(elr);\r
-                                               resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DB_PROBLEM_MSG);\r
-                                       }\r
-                                       return;\r
-                               }\r
-                       }\r
-               }\r
-               resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Bad URL.");\r
-       }\r
-       /**\r
-        * Get some information (such as a parameter) underneath the /internal/ namespace.\r
-        * See the <b>Internal API</b> document for details on how this method should be invoked.\r
-        */\r
-       @Override\r
-       public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
-               setIpAndFqdnForEelf("doGet");\r
-               eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_FEEDID, req.getHeader(BEHALF_HEADER),getIdFromPath(req)+"");\r
-               String path = req.getPathInfo();\r
-               if (path.equals("/halt") && !req.isSecure()) {\r
-                       // request to halt the server - can ONLY come from localhost\r
-                       String remote = req.getRemoteAddr();\r
-                       if (remote.equals("127.0.0.1")) {\r
-                               intlogger.info("PROV0009 Request to HALT received.");\r
-                               resp.setStatus(HttpServletResponse.SC_OK);\r
-                               Main.shutdown();\r
-                       } else {\r
-                               intlogger.info("PROV0010 Disallowed request to HALT received from "+remote);\r
-                               resp.setStatus(HttpServletResponse.SC_FORBIDDEN);\r
-                       }\r
-                       return;\r
-               }\r
-\r
-               EventLogRecord elr = new EventLogRecord(req);\r
-               if (!isAuthorizedForInternal(req)) {\r
-                       elr.setMessage("Unauthorized.");\r
-                       elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
-                       eventlogger.info(elr);\r
-                       resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthorized.");\r
-                       return;\r
-               }\r
-               if (path.equals("/fetchProv") && !req.isSecure()) {\r
-                       // if request came from active_pod or standby_pod and it is not us, reload prov data\r
-                       SynchronizerTask s = SynchronizerTask.getSynchronizer();\r
-                       s.doFetch();\r
-                       resp.setStatus(HttpServletResponse.SC_OK);\r
-                       return;\r
-               }\r
-               if (path.equals("/prov")) {\r
-                       if (isProxyOK(req) && isProxyServer()) {\r
-                               if (super.doGetWithFallback(req, resp))\r
-                                       return;\r
-                               // fall back to returning the local data if the remote is unreachable\r
-                               intlogger.info("Active server unavailable; falling back to local copy.");\r
-                       }\r
-                       Poker p = Poker.getPoker();\r
-                       resp.setStatus(HttpServletResponse.SC_OK);\r
-                       resp.setContentType(PROVFULL_CONTENT_TYPE2);\r
-                       resp.getOutputStream().print(p.getProvisioningString());\r
-                       return;\r
-               }\r
-               if (path.equals("/logs") || path.equals("/logs/")) {\r
-                       resp.setStatus(HttpServletResponse.SC_OK);\r
-                       resp.setContentType("application/json");\r
-                       resp.getOutputStream().print(generateLogfileList().toString());\r
-                       return;\r
-               }\r
-               if (path.startsWith("/logs/")) {\r
-                       Properties p = (new DB()).getProperties();\r
-                       String logdir = p.getProperty("org.onap.dmaap.datarouter.provserver.accesslog.dir");\r
-                       String logfile = path.substring(6);\r
-                       if (logdir != null && logfile != null && logfile.indexOf('/') < 0) {\r
-                               File log = new File(logdir + "/" + logfile);\r
-                               if (log.exists() && log.isFile()) {\r
-                                       resp.setStatus(HttpServletResponse.SC_OK);\r
-                                       resp.setContentType("text/plain");\r
-                                       Path logpath = Paths.get(log.getAbsolutePath());\r
-                                       Files.copy(logpath, resp.getOutputStream());\r
-                                       return;\r
-                               }\r
-                       }\r
-                       resp.sendError(HttpServletResponse.SC_NO_CONTENT, "No file.");\r
-                       return;\r
-               }\r
-               if (path.startsWith("/api/")) {\r
-                       if (isProxyOK(req) && isProxyServer()) {\r
-                               super.doGet(req, resp);\r
-                               return;\r
-                       }\r
-                       String key = path.substring(5);\r
-                       if (key.length() > 0) {\r
-                               Parameters param = Parameters.getParameter(key);\r
-                               if (param != null) {\r
-                                       resp.setStatus(HttpServletResponse.SC_OK);\r
-                                       resp.setContentType("text/plain");\r
-                                       resp.getOutputStream().print(param.getValue() + "\n");\r
-                                       return;\r
-                               }\r
-                       }\r
-               }\r
-               if (path.equals("/drlogs") || path.equals("/drlogs/")) {\r
-                       // Special POD <=> POD API to determine what log file records are loaded here\r
-                       LogfileLoader lfl = LogfileLoader.getLoader();\r
-                       resp.setStatus(HttpServletResponse.SC_OK);\r
-                       resp.setContentType("text/plain");\r
-                       resp.getOutputStream().print(lfl.getBitSet().toString());\r
-                       return;\r
-               }\r
-               resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Bad URL.");\r
-       }\r
-       /**\r
-        * Modify a parameter at the address /internal/api/&lt;parameter&gt;.\r
-        * See the <b>Internal API</b> document for details on how this method should be invoked.\r
-        */\r
-       @Override\r
-       public void doPut(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
-               setIpAndFqdnForEelf("doPut");\r
-               eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_FEEDID, req.getHeader(BEHALF_HEADER),getIdFromPath(req)+"");\r
-               EventLogRecord elr = new EventLogRecord(req);\r
-               if (!isAuthorizedForInternal(req)) {\r
-                       elr.setMessage("Unauthorized.");\r
-                       elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
-                       eventlogger.info(elr);\r
-                       resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthorized.");\r
-                       return;\r
-               }\r
-               String path = req.getPathInfo();\r
-               if (path.startsWith("/api/")) {\r
-                       if (isProxyOK(req) && isProxyServer()) {\r
-                               super.doPut(req, resp);\r
-                               return;\r
-                       }\r
-                       String key = path.substring(5);\r
-                       if (key.length() > 0) {\r
-                               Parameters param = Parameters.getParameter(key);\r
-                               if (param != null) {\r
-                                       String t = catValues(req.getParameterValues("val"));\r
-                                       param.setValue(t);\r
-                                       if (doUpdate(param)) {\r
-                                               elr.setResult(HttpServletResponse.SC_OK);\r
-                                               eventlogger.info(elr);\r
-                                               resp.setStatus(HttpServletResponse.SC_OK);\r
-                                               provisioningDataChanged();\r
-                                               provisioningParametersChanged();\r
-                                       } else {\r
-                                               // Something went wrong with the UPDATE\r
-                                               elr.setResult(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\r
-                                               eventlogger.info(elr);\r
-                                               resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DB_PROBLEM_MSG);\r
-                                       }\r
-                                       return;\r
-                               }\r
-                       }\r
-               }\r
-               resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Bad URL.");\r
-       }\r
-       /**\r
-        * Create some new information (such as a parameter or log entries) underneath the /internal/ namespace.\r
-        * See the <b>Internal API</b> document for details on how this method should be invoked.\r
-        */\r
-       @SuppressWarnings("resource")\r
-       @Override\r
-       public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
-               setIpAndFqdnForEelf("doPost");\r
-               eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF, req.getHeader(BEHALF_HEADER));\r
-               EventLogRecord elr = new EventLogRecord(req);\r
-               if (!isAuthorizedForInternal(req)) {\r
-                       elr.setMessage("Unauthorized.");\r
-                       elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
-                       eventlogger.info(elr);\r
-                       resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthorized.");\r
-                       return;\r
-               }\r
-\r
-               String path = req.getPathInfo();\r
-               if (path.startsWith("/api/")) {\r
-                       if (isProxyOK(req) && isProxyServer()) {\r
-                               super.doPost(req, resp);\r
-                               return;\r
-                       }\r
-                       String key = path.substring(5);\r
-                       if (key.length() > 0) {\r
-                               Parameters param = Parameters.getParameter(key);\r
-                               if (param == null) {\r
-                                       String t = catValues(req.getParameterValues("val"));\r
-                                       param = new Parameters(key, t);\r
-                                       if (doInsert(param)) {\r
-                                               elr.setResult(HttpServletResponse.SC_OK);\r
-                                               eventlogger.info(elr);\r
-                                               resp.setStatus(HttpServletResponse.SC_OK);\r
-                                               provisioningDataChanged();\r
-                                               provisioningParametersChanged();\r
-                                       } else {\r
-                                               // Something went wrong with the INSERT\r
-                                               elr.setResult(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\r
-                                               eventlogger.info(elr);\r
-                                               resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DB_PROBLEM_MSG);\r
-                                       }\r
-                                       return;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               if (path.equals("/logs") || path.equals("/logs/")) {\r
-                       String ctype = req.getHeader("Content-Type");\r
-                       if (ctype == null || !ctype.equals("text/plain")) {\r
-                               elr.setResult(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);\r
-                               elr.setMessage("Bad media type: "+ctype);\r
-                               resp.setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);\r
-                               eventlogger.info(elr);\r
-                               return;\r
-                       }\r
-                       String spooldir = (new DB()).getProperties().getProperty("org.onap.dmaap.datarouter.provserver.spooldir");\r
-                       String spoolname = String.format("%d-%d-", System.currentTimeMillis(), Thread.currentThread().getId());\r
-                       synchronized (logseq) {\r
-                               // perhaps unnecessary, but it helps make the name unique\r
-                               spoolname += logseq.toString();\r
-                               logseq++;\r
-                       }\r
-                       String encoding = req.getHeader("Content-Encoding");\r
-                       if (encoding != null) {\r
-                               if (encoding.trim().equals("gzip")) {\r
-                                       spoolname += ".gz";\r
-                               } else {\r
-                                       elr.setResult(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);\r
-                                       resp.setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);\r
-                                       eventlogger.info(elr);\r
-                                       return;\r
-                               }\r
-                       }\r
-                       // Determine space available -- available space must be at least 5%\r
-                       FileSystem fs = (Paths.get(spooldir)).getFileSystem();\r
-                       long total = 0;\r
-                       long avail = 0;\r
-                       for (FileStore store: fs.getFileStores()) {\r
-                               total += store.getTotalSpace();\r
-                               avail += store.getUsableSpace();\r
-                       }\r
-                       try { fs.close(); } catch (Exception e) { }\r
-                       if (((avail * 100) / total) < 5) {\r
-                               elr.setResult(HttpServletResponse.SC_SERVICE_UNAVAILABLE);\r
-                               resp.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);\r
-                               eventlogger.info(elr);\r
-                               return;\r
-                       }\r
-                       Path tmppath = Paths.get(spooldir, spoolname);\r
-                       Path donepath = Paths.get(spooldir, "IN."+spoolname);\r
-                       Files.copy(req.getInputStream(), Paths.get(spooldir, spoolname), StandardCopyOption.REPLACE_EXISTING);\r
-                       Files.move(tmppath, donepath, StandardCopyOption.REPLACE_EXISTING);\r
-                       elr.setResult(HttpServletResponse.SC_CREATED);\r
-                       resp.setStatus(HttpServletResponse.SC_CREATED);\r
-                       eventlogger.info(elr);\r
-                       LogfileLoader.getLoader();      // This starts the logfile loader "task"\r
-                       return;\r
-               }\r
-\r
-               if (path.equals("/drlogs") || path.equals("/drlogs/")) {\r
-                       // Receive post request and generate log entries\r
-                       String ctype = req.getHeader("Content-Type");\r
-                       if (ctype == null || !ctype.equals("text/plain")) {\r
-                               elr.setResult(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);\r
-                               elr.setMessage("Bad media type: "+ctype);\r
-                               resp.setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);\r
-                               eventlogger.info(elr);\r
-                               return;\r
-                       }\r
-                       InputStream is = req.getInputStream();\r
-                       ByteArrayOutputStream bos = new ByteArrayOutputStream();\r
-                       int ch = 0;\r
-                       while ((ch = is.read()) >= 0)\r
-                               bos.write(ch);\r
-                       RLEBitSet bs = new RLEBitSet(bos.toString());   // The set of records to retrieve\r
-                       elr.setResult(HttpServletResponse.SC_OK);\r
-                       resp.setStatus(HttpServletResponse.SC_OK);\r
-                       resp.setContentType("text/plain");\r
-                       LogRecord.printLogRecords(resp.getOutputStream(), bs);\r
-                       eventlogger.info(elr);\r
-                       return;\r
-               }\r
-\r
-               elr.setResult(HttpServletResponse.SC_NOT_FOUND);\r
-               resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Bad URL.");\r
-               eventlogger.info(elr);\r
-       }\r
-\r
-       private String catValues(String[] v) {\r
-               StringBuilder sb = new StringBuilder();\r
-               if (v != null) {\r
-                       String pfx = "";\r
-                       for (String s : v) {\r
-                               sb.append(pfx);\r
-                               sb.append(s);\r
-                               pfx = "|";\r
-                       }\r
-               }\r
-               return sb.toString();\r
-       }\r
-       private JSONArray generateLogfileList() {\r
-               JSONArray ja = new JSONArray();\r
-               Properties p = (new DB()).getProperties();\r
-               String s = p.getProperty("org.onap.dmaap.datarouter.provserver.accesslog.dir");\r
-               if (s != null) {\r
-                       String[] dirs = s.split(",");\r
-                       for (String dir : dirs) {\r
-                               File f = new File(dir);\r
-                               String[] list = f.list();\r
-                               if (list != null) {\r
-                                       for (String s2 : list) {\r
-                                               if (!s2.startsWith("."))\r
-                                                       ja.put(s2);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               return ja;\r
-       }\r
-}\r
+/*******************************************************************************
+ * ============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 java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.Properties;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.json.JSONArray;
+import org.onap.dmaap.datarouter.provisioning.beans.EventLogRecord;
+import org.onap.dmaap.datarouter.provisioning.beans.LogRecord;
+import org.onap.dmaap.datarouter.provisioning.beans.Parameters;
+import org.onap.dmaap.datarouter.provisioning.eelf.EelfMsgs;
+import org.onap.dmaap.datarouter.provisioning.utils.DB;
+import org.onap.dmaap.datarouter.provisioning.utils.LogfileLoader;
+import org.onap.dmaap.datarouter.provisioning.utils.RLEBitSet;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+/**
+ * <p>
+ * This servlet handles requests to URLs under /internal on the provisioning server.
+ * These include:
+ * </p>
+ * <div class="contentContainer">
+ * <table class="packageSummary" border="0" cellpadding="3" cellspacing="0">
+ * <caption><span>URL Path Summary</span><span class="tabEnd">&nbsp;</span></caption>
+ * <tr>
+ *   <th class="colFirst" width="15%">URL Path</th>
+ *   <th class="colOne">Method</th>
+ *   <th class="colLast">Purpose</th>
+ * </tr>
+ * <tr class="altColor">
+ *   <td class="colFirst">/internal/prov</td>
+ *   <td class="colOne">GET</td>
+ *   <td class="colLast">used to GET a full JSON copy of the provisioning data.</td>
+ * </tr>
+ * <tr class="rowColor">
+ *   <td class="colFirst">/internal/fetchProv</td>
+ *   <td class="colOne">GET</td>
+ *   <td class="colLast">used to signal to a standby POD that the provisioning data should be fetched from the active POD.</td>
+ * </tr>
+ * <tr class="altColor">
+ *   <td class="colFirst" rowspan="2">/internal/logs</td>
+ *   <td class="colOne">GET</td>
+ *   <td class="colLast">used to GET an index of log files and individual logs for this provisioning server.</td>
+ * </tr>
+ * <tr class="altColor">
+ *   <td class="colOne">POST</td>
+ *   <td class="colLast">used to POST log files from the individual nodes to this provisioning server.</td>
+ * </tr>
+ * <tr class="rowColor">
+ *   <td class="colFirst" rowspan="4">/internal/api</td>
+ *   <td class="colOne">GET</td>
+ *   <td class="colLast">used to GET an individual parameter value. The parameter name is specified by the path after /api/.</td>
+ * </tr>
+ * <tr class="rowColor">
+ *   <td class="colOne">PUT</td>
+ *   <td class="colLast">used to set an individual parameter value. The parameter name is specified by the path after /api/.</td>
+ * </tr>
+ * <tr class="rowColor">
+ *   <td class="colOne">DELETE</td>
+ *   <td class="colLast">used to remove an individual parameter value. The parameter name is specified by the path after /api/.</td>
+ * </tr>
+ * <tr class="rowColor">
+ *   <td class="colOne">POST</td>
+ *   <td class="colLast">used to create a new individual parameter value. The parameter name is specified by the path after /api/.</td>
+ * </tr>
+ * <tr class="altColor">
+ *   <td class="colFirst">/internal/halt</td>
+ *   <td class="colOne">GET</td>
+ *   <td class="colLast">used to halt the server (must be accessed from 127.0.0.1).</td>
+ * </tr>
+ * <tr class="rowColor">
+ *   <td class="colFirst" rowspan="2">/internal/drlogs</td>
+ *   <td class="colOne">GET</td>
+ *   <td class="colLast">used to get a list of DR log entries available for retrieval.
+ *   Note: these are the actual data router log entries sent to the provisioning server
+ *   by the nodes, not the provisioning server's internal logs (access via /internal/logs above).
+ *   The range is returned as a list of record sequence numbers.</td>
+ * </tr>
+ * <tr class="rowColor">
+ *   <td class="colOne">POST</td>
+ *   <td class="colLast">used to retrieve specific log entries.
+ *   The sequence numbers of the records to fetch are POST-ed; the records matching the sequence numbers are returned.</td>
+ * </tr>
+ * <tr class="altColor">
+ *   <td class="colFirst">/internal/route/*</td>
+ *   <td class="colOne">*</td>
+ *   <td class="colLast">URLs under this path are handled via the {@link org.onap.dmaap.datarouter.provisioning.RouteServlet}</td>
+ * </tr>
+ * </table>
+ * </div>
+ * <p>
+ * Authorization to use these URLs is a little different than for other URLs on the provisioning server.
+ * For the most part, the IP address that the request comes from should be either:
+ * </p>
+ * <ol>
+ * <li>an IP address of a provisioning server, or</li>
+ * <li>the IP address of a node (to allow access to /internal/prov), or</li>
+ * <li>an IP address from the "<i>special subnet</i>" which is configured with
+ * the PROV_SPECIAL_SUBNET parameter.
+ * </ol>
+ * <p>
+ * In addition, requests to /internal/halt can ONLY come from localhost (127.0.0.1) on the HTTP port.
+ * </p>
+ * <p>
+ * All DELETE/GET/PUT/POST requests made to /internal/api on this servlet on the standby server are
+ * proxied to the active server (using the {@link ProxyServlet}) if it is up and reachable.
+ * </p>
+ *
+ * @author Robert Eby
+ * @version $Id: InternalServlet.java,v 1.23 2014/03/24 18:47:10 eby Exp $
+ */
+@SuppressWarnings("serial")
+public class InternalServlet extends ProxyServlet {
+    private static Integer logseq = new Integer(0); // another piece of info to make log spool file names unique
+    //Adding EELF Logger Rally:US664892
+    private static EELFLogger eelflogger = EELFManager.getInstance().getLogger("org.onap.dmaap.datarouter.provisioning.InternalServlet");
+
+    /**
+     * Delete a parameter at the address /internal/api/&lt;parameter&gt;.
+     * See the <b>Internal API</b> document for details on how this method should be invoked.
+     */
+    @Override
+    public void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        setIpAndFqdnForEelf("doDelete");
+        eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_FEEDID, req.getHeader(BEHALF_HEADER),getIdFromPath(req)+"");
+        EventLogRecord elr = new EventLogRecord(req);
+        if (!isAuthorizedForInternal(req)) {
+            elr.setMessage("Unauthorized.");
+            elr.setResult(HttpServletResponse.SC_FORBIDDEN);
+            eventlogger.info(elr);
+            resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthorized.");
+            return;
+        }
+
+        String path = req.getPathInfo();
+        if (path.startsWith("/api/")) {
+            if (isProxyOK(req) && isProxyServer()) {
+                super.doDelete(req, resp);
+                return;
+            }
+            String key = path.substring(5);
+            if (key.length() > 0) {
+                Parameters param = Parameters.getParameter(key);
+                if (param != null) {
+                    if (doDelete(param)) {
+                        elr.setResult(HttpServletResponse.SC_OK);
+                        eventlogger.info(elr);
+                        resp.setStatus(HttpServletResponse.SC_OK);
+                        provisioningDataChanged();
+                        provisioningParametersChanged();
+                    } else {
+                        // Something went wrong with the DELETE
+                        elr.setResult(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+                        eventlogger.info(elr);
+                        resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DB_PROBLEM_MSG);
+                    }
+                    return;
+                }
+            }
+        }
+        resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Bad URL.");
+    }
+    /**
+     * Get some information (such as a parameter) underneath the /internal/ namespace.
+     * See the <b>Internal API</b> document for details on how this method should be invoked.
+     */
+    @Override
+    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        setIpAndFqdnForEelf("doGet");
+        eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_FEEDID, req.getHeader(BEHALF_HEADER),getIdFromPath(req)+"");
+        String path = req.getPathInfo();
+        if (path.equals("/halt") && !req.isSecure()) {
+            // request to halt the server - can ONLY come from localhost
+            String remote = req.getRemoteAddr();
+            if (remote.equals("127.0.0.1")) {
+                intlogger.info("PROV0009 Request to HALT received.");
+                resp.setStatus(HttpServletResponse.SC_OK);
+                Main.shutdown();
+            } else {
+                intlogger.info("PROV0010 Disallowed request to HALT received from "+remote);
+                resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
+            }
+            return;
+        }
+
+        EventLogRecord elr = new EventLogRecord(req);
+        if (!isAuthorizedForInternal(req)) {
+            elr.setMessage("Unauthorized.");
+            elr.setResult(HttpServletResponse.SC_FORBIDDEN);
+            eventlogger.info(elr);
+            resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthorized.");
+            return;
+        }
+        if (path.equals("/fetchProv") && !req.isSecure()) {
+            // if request came from active_pod or standby_pod and it is not us, reload prov data
+            SynchronizerTask s = SynchronizerTask.getSynchronizer();
+            s.doFetch();
+            resp.setStatus(HttpServletResponse.SC_OK);
+            return;
+        }
+        if (path.equals("/prov")) {
+            if (isProxyOK(req) && isProxyServer()) {
+                if (super.doGetWithFallback(req, resp))
+                    return;
+                // fall back to returning the local data if the remote is unreachable
+                intlogger.info("Active server unavailable; falling back to local copy.");
+            }
+            Poker p = Poker.getPoker();
+            resp.setStatus(HttpServletResponse.SC_OK);
+            resp.setContentType(PROVFULL_CONTENT_TYPE2);
+            resp.getOutputStream().print(p.getProvisioningString());
+            return;
+        }
+        if (path.equals("/logs") || path.equals("/logs/")) {
+            resp.setStatus(HttpServletResponse.SC_OK);
+            resp.setContentType("application/json");
+            resp.getOutputStream().print(generateLogfileList().toString());
+            return;
+        }
+        if (path.startsWith("/logs/")) {
+            Properties p = (new DB()).getProperties();
+            String logdir = p.getProperty("org.onap.dmaap.datarouter.provserver.accesslog.dir");
+            String logfile = path.substring(6);
+            if (logdir != null && logfile != null && logfile.indexOf('/') < 0) {
+                File log = new File(logdir + "/" + logfile);
+                if (log.exists() && log.isFile()) {
+                    resp.setStatus(HttpServletResponse.SC_OK);
+                    resp.setContentType("text/plain");
+                    Path logpath = Paths.get(log.getAbsolutePath());
+                    Files.copy(logpath, resp.getOutputStream());
+                    return;
+                }
+            }
+            resp.sendError(HttpServletResponse.SC_NO_CONTENT, "No file.");
+            return;
+        }
+        if (path.startsWith("/api/")) {
+            if (isProxyOK(req) && isProxyServer()) {
+                super.doGet(req, resp);
+                return;
+            }
+            String key = path.substring(5);
+            if (key.length() > 0) {
+                Parameters param = Parameters.getParameter(key);
+                if (param != null) {
+                    resp.setStatus(HttpServletResponse.SC_OK);
+                    resp.setContentType("text/plain");
+                    resp.getOutputStream().print(param.getValue() + "\n");
+                    return;
+                }
+            }
+        }
+        if (path.equals("/drlogs") || path.equals("/drlogs/")) {
+            // Special POD <=> POD API to determine what log file records are loaded here
+            LogfileLoader lfl = LogfileLoader.getLoader();
+            resp.setStatus(HttpServletResponse.SC_OK);
+            resp.setContentType("text/plain");
+            resp.getOutputStream().print(lfl.getBitSet().toString());
+            return;
+        }
+        resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Bad URL.");
+    }
+    /**
+     * Modify a parameter at the address /internal/api/&lt;parameter&gt;.
+     * See the <b>Internal API</b> document for details on how this method should be invoked.
+     */
+    @Override
+    public void doPut(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        setIpAndFqdnForEelf("doPut");
+        eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_FEEDID, req.getHeader(BEHALF_HEADER),getIdFromPath(req)+"");
+        EventLogRecord elr = new EventLogRecord(req);
+        if (!isAuthorizedForInternal(req)) {
+            elr.setMessage("Unauthorized.");
+            elr.setResult(HttpServletResponse.SC_FORBIDDEN);
+            eventlogger.info(elr);
+            resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthorized.");
+            return;
+        }
+        String path = req.getPathInfo();
+        if (path.startsWith("/api/")) {
+            if (isProxyOK(req) && isProxyServer()) {
+                super.doPut(req, resp);
+                return;
+            }
+            String key = path.substring(5);
+            if (key.length() > 0) {
+                Parameters param = Parameters.getParameter(key);
+                if (param != null) {
+                    String t = catValues(req.getParameterValues("val"));
+                    param.setValue(t);
+                    if (doUpdate(param)) {
+                        elr.setResult(HttpServletResponse.SC_OK);
+                        eventlogger.info(elr);
+                        resp.setStatus(HttpServletResponse.SC_OK);
+                        provisioningDataChanged();
+                        provisioningParametersChanged();
+                    } else {
+                        // Something went wrong with the UPDATE
+                        elr.setResult(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+                        eventlogger.info(elr);
+                        resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DB_PROBLEM_MSG);
+                    }
+                    return;
+                }
+            }
+        }
+        resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Bad URL.");
+    }
+    /**
+     * Create some new information (such as a parameter or log entries) underneath the /internal/ namespace.
+     * See the <b>Internal API</b> document for details on how this method should be invoked.
+     */
+    @SuppressWarnings("resource")
+    @Override
+    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        setIpAndFqdnForEelf("doPost");
+        eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF, req.getHeader(BEHALF_HEADER));
+        EventLogRecord elr = new EventLogRecord(req);
+        if (!isAuthorizedForInternal(req)) {
+            elr.setMessage("Unauthorized.");
+            elr.setResult(HttpServletResponse.SC_FORBIDDEN);
+            eventlogger.info(elr);
+            resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthorized.");
+            return;
+        }
+
+        String path = req.getPathInfo();
+        if (path.startsWith("/api/")) {
+            if (isProxyOK(req) && isProxyServer()) {
+                super.doPost(req, resp);
+                return;
+            }
+            String key = path.substring(5);
+            if (key.length() > 0) {
+                Parameters param = Parameters.getParameter(key);
+                if (param == null) {
+                    String t = catValues(req.getParameterValues("val"));
+                    param = new Parameters(key, t);
+                    if (doInsert(param)) {
+                        elr.setResult(HttpServletResponse.SC_OK);
+                        eventlogger.info(elr);
+                        resp.setStatus(HttpServletResponse.SC_OK);
+                        provisioningDataChanged();
+                        provisioningParametersChanged();
+                    } else {
+                        // Something went wrong with the INSERT
+                        elr.setResult(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+                        eventlogger.info(elr);
+                        resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DB_PROBLEM_MSG);
+                    }
+                    return;
+                }
+            }
+        }
+
+        if (path.equals("/logs") || path.equals("/logs/")) {
+            String ctype = req.getHeader("Content-Type");
+            if (ctype == null || !ctype.equals("text/plain")) {
+                elr.setResult(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
+                elr.setMessage("Bad media type: "+ctype);
+                resp.setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
+                eventlogger.info(elr);
+                return;
+            }
+            String spooldir = (new DB()).getProperties().getProperty("org.onap.dmaap.datarouter.provserver.spooldir");
+            String spoolname = String.format("%d-%d-", System.currentTimeMillis(), Thread.currentThread().getId());
+            synchronized (logseq) {
+                // perhaps unnecessary, but it helps make the name unique
+                spoolname += logseq.toString();
+                logseq++;
+            }
+            String encoding = req.getHeader("Content-Encoding");
+            if (encoding != null) {
+                if (encoding.trim().equals("gzip")) {
+                    spoolname += ".gz";
+                } else {
+                    elr.setResult(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
+                    resp.setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
+                    eventlogger.info(elr);
+                    return;
+                }
+            }
+            // Determine space available -- available space must be at least 5%
+            FileSystem fs = (Paths.get(spooldir)).getFileSystem();
+            long total = 0;
+            long avail = 0;
+            for (FileStore store: fs.getFileStores()) {
+                total += store.getTotalSpace();
+                avail += store.getUsableSpace();
+            }
+            try { fs.close(); } catch (Exception e) { }
+            if (((avail * 100) / total) < 5) {
+                elr.setResult(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+                resp.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+                eventlogger.info(elr);
+                return;
+            }
+            Path tmppath = Paths.get(spooldir, spoolname);
+            Path donepath = Paths.get(spooldir, "IN."+spoolname);
+            Files.copy(req.getInputStream(), Paths.get(spooldir, spoolname), StandardCopyOption.REPLACE_EXISTING);
+            Files.move(tmppath, donepath, StandardCopyOption.REPLACE_EXISTING);
+            elr.setResult(HttpServletResponse.SC_CREATED);
+            resp.setStatus(HttpServletResponse.SC_CREATED);
+            eventlogger.info(elr);
+            LogfileLoader.getLoader();    // This starts the logfile loader "task"
+            return;
+        }
+
+        if (path.equals("/drlogs") || path.equals("/drlogs/")) {
+            // Receive post request and generate log entries
+            String ctype = req.getHeader("Content-Type");
+            if (ctype == null || !ctype.equals("text/plain")) {
+                elr.setResult(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
+                elr.setMessage("Bad media type: "+ctype);
+                resp.setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
+                eventlogger.info(elr);
+                return;
+            }
+            InputStream is = req.getInputStream();
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            int ch = 0;
+            while ((ch = is.read()) >= 0)
+                bos.write(ch);
+            RLEBitSet bs = new RLEBitSet(bos.toString());    // The set of records to retrieve
+            elr.setResult(HttpServletResponse.SC_OK);
+            resp.setStatus(HttpServletResponse.SC_OK);
+            resp.setContentType("text/plain");
+            LogRecord.printLogRecords(resp.getOutputStream(), bs);
+            eventlogger.info(elr);
+            return;
+        }
+
+        elr.setResult(HttpServletResponse.SC_NOT_FOUND);
+        resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Bad URL.");
+        eventlogger.info(elr);
+    }
+
+    private String catValues(String[] v) {
+        StringBuilder sb = new StringBuilder();
+        if (v != null) {
+            String pfx = "";
+            for (String s : v) {
+                sb.append(pfx);
+                sb.append(s);
+                pfx = "|";
+            }
+        }
+        return sb.toString();
+    }
+    private JSONArray generateLogfileList() {
+        JSONArray ja = new JSONArray();
+        Properties p = (new DB()).getProperties();
+        String s = p.getProperty("org.onap.dmaap.datarouter.provserver.accesslog.dir");
+        if (s != null) {
+            String[] dirs = s.split(",");
+            for (String dir : dirs) {
+                File f = new File(dir);
+                String[] list = f.list();
+                if (list != null) {
+                    for (String s2 : list) {
+                        if (!s2.startsWith("."))
+                            ja.put(s2);
+                    }
+                }
+            }
+        }
+        return ja;
+    }
+}