[DMAAP-48] Initial code import
[dmaap/datarouter.git] / datarouter-prov / src / main / java / com / att / research / datarouter / provisioning / InternalServlet.java
1 /*******************************************************************************\r
2  * ============LICENSE_START==================================================\r
3  * * org.onap.dmaap\r
4  * * ===========================================================================\r
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
6  * * ===========================================================================\r
7  * * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * * you may not use this file except in compliance with the License.\r
9  * * You may obtain a copy of the License at\r
10  * * \r
11  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  * * \r
13  *  * Unless required by applicable law or agreed to in writing, software\r
14  * * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * * See the License for the specific language governing permissions and\r
17  * * limitations under the License.\r
18  * * ============LICENSE_END====================================================\r
19  * *\r
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
21  * *\r
22  ******************************************************************************/\r
23 \r
24 \r
25 package com.att.research.datarouter.provisioning;\r
26 \r
27 import java.io.ByteArrayOutputStream;\r
28 import java.io.File;\r
29 import java.io.IOException;\r
30 import java.io.InputStream;\r
31 import java.nio.file.FileStore;\r
32 import java.nio.file.FileSystem;\r
33 import java.nio.file.Files;\r
34 import java.nio.file.Path;\r
35 import java.nio.file.Paths;\r
36 import java.nio.file.StandardCopyOption;\r
37 import java.util.Properties;\r
38 \r
39 import javax.servlet.http.HttpServletRequest;\r
40 import javax.servlet.http.HttpServletResponse;\r
41 \r
42 import org.json.JSONArray;\r
43 \r
44 import com.att.eelf.configuration.EELFLogger;\r
45 import com.att.eelf.configuration.EELFManager;\r
46 import com.att.research.datarouter.provisioning.beans.EventLogRecord;\r
47 import com.att.research.datarouter.provisioning.beans.LogRecord;\r
48 import com.att.research.datarouter.provisioning.beans.Parameters;\r
49 import com.att.research.datarouter.provisioning.eelf.EelfMsgs;\r
50 import com.att.research.datarouter.provisioning.utils.DB;\r
51 import com.att.research.datarouter.provisioning.utils.RLEBitSet;\r
52 import com.att.research.datarouter.provisioning.utils.LogfileLoader;\r
53 \r
54 /**\r
55  * <p>\r
56  * This servlet handles requests to URLs under /internal on the provisioning server.\r
57  * These include:\r
58  * </p>\r
59  * <div class="contentContainer">\r
60  * <table class="packageSummary" border="0" cellpadding="3" cellspacing="0">\r
61  * <caption><span>URL Path Summary</span><span class="tabEnd">&nbsp;</span></caption>\r
62  * <tr>\r
63  *   <th class="colFirst" width="15%">URL Path</th>\r
64  *   <th class="colOne">Method</th>\r
65  *   <th class="colLast">Purpose</th>\r
66  * </tr>\r
67  * <tr class="altColor">\r
68  *   <td class="colFirst">/internal/prov</td>\r
69  *   <td class="colOne">GET</td>\r
70  *   <td class="colLast">used to GET a full JSON copy of the provisioning data.</td>\r
71  * </tr>\r
72  * <tr class="rowColor">\r
73  *   <td class="colFirst">/internal/fetchProv</td>\r
74  *   <td class="colOne">GET</td>\r
75  *   <td class="colLast">used to signal to a standby POD that the provisioning data should be fetched from the active POD.</td>\r
76  * </tr>\r
77  * <tr class="altColor">\r
78  *   <td class="colFirst" rowspan="2">/internal/logs</td>\r
79  *   <td class="colOne">GET</td>\r
80  *   <td class="colLast">used to GET an index of log files and individual logs for this provisioning server.</td>\r
81  * </tr>\r
82  * <tr class="altColor">\r
83  *   <td class="colOne">POST</td>\r
84  *   <td class="colLast">used to POST log files from the individual nodes to this provisioning server.</td>\r
85  * </tr>\r
86  * <tr class="rowColor">\r
87  *   <td class="colFirst" rowspan="4">/internal/api</td>\r
88  *   <td class="colOne">GET</td>\r
89  *   <td class="colLast">used to GET an individual parameter value. The parameter name is specified by the path after /api/.</td>\r
90  * </tr>\r
91  * <tr class="rowColor">\r
92  *   <td class="colOne">PUT</td>\r
93  *   <td class="colLast">used to set an individual parameter value. The parameter name is specified by the path after /api/.</td>\r
94  * </tr>\r
95  * <tr class="rowColor">\r
96  *   <td class="colOne">DELETE</td>\r
97  *   <td class="colLast">used to remove an individual parameter value. The parameter name is specified by the path after /api/.</td>\r
98  * </tr>\r
99  * <tr class="rowColor">\r
100  *   <td class="colOne">POST</td>\r
101  *   <td class="colLast">used to create a new individual parameter value. The parameter name is specified by the path after /api/.</td>\r
102  * </tr>\r
103  * <tr class="altColor">\r
104  *   <td class="colFirst">/internal/halt</td>\r
105  *   <td class="colOne">GET</td>\r
106  *   <td class="colLast">used to halt the server (must be accessed from 127.0.0.1).</td>\r
107  * </tr>\r
108  * <tr class="rowColor">\r
109  *   <td class="colFirst" rowspan="2">/internal/drlogs</td>\r
110  *   <td class="colOne">GET</td>\r
111  *   <td class="colLast">used to get a list of DR log entries available for retrieval.\r
112  *   Note: these are the actual data router log entries sent to the provisioning server\r
113  *   by the nodes, not the provisioning server's internal logs (access via /internal/logs above).\r
114  *   The range is returned as a list of record sequence numbers.</td>\r
115  * </tr>\r
116  * <tr class="rowColor">\r
117  *   <td class="colOne">POST</td>\r
118  *   <td class="colLast">used to retrieve specific log entries.\r
119  *   The sequence numbers of the records to fetch are POST-ed; the records matching the sequence numbers are returned.</td>\r
120  * </tr>\r
121  * <tr class="altColor">\r
122  *   <td class="colFirst">/internal/route/*</td>\r
123  *   <td class="colOne">*</td>\r
124  *   <td class="colLast">URLs under this path are handled via the {@link com.att.research.datarouter.provisioning.RouteServlet}</td>\r
125  * </tr>\r
126  * </table>\r
127  * </div>\r
128  * <p>\r
129  * Authorization to use these URLs is a little different than for other URLs on the provisioning server.\r
130  * For the most part, the IP address that the request comes from should be either:\r
131  * </p>\r
132  * <ol>\r
133  * <li>an IP address of a provisioning server, or</li>\r
134  * <li>the IP address of a node (to allow access to /internal/prov), or</li>\r
135  * <li>an IP address from the "<i>special subnet</i>" which is configured with\r
136  * the PROV_SPECIAL_SUBNET parameter.\r
137  * </ol>\r
138  * <p>\r
139  * In addition, requests to /internal/halt can ONLY come from localhost (127.0.0.1) on the HTTP port.\r
140  * </p>\r
141  * <p>\r
142  * All DELETE/GET/PUT/POST requests made to /internal/api on this servlet on the standby server are\r
143  * proxied to the active server (using the {@link ProxyServlet}) if it is up and reachable.\r
144  * </p>\r
145  *\r
146  * @author Robert Eby\r
147  * @version $Id: InternalServlet.java,v 1.23 2014/03/24 18:47:10 eby Exp $\r
148  */\r
149 @SuppressWarnings("serial")\r
150 public class InternalServlet extends ProxyServlet {\r
151         private static Integer logseq = new Integer(0); // another piece of info to make log spool file names unique\r
152         //Adding EELF Logger Rally:US664892 \r
153     private static EELFLogger eelflogger = EELFManager.getInstance().getLogger("com.att.research.datarouter.provisioning.InternalServlet");\r
154 \r
155         /**\r
156          * Delete a parameter at the address /internal/api/&lt;parameter&gt;.\r
157          * See the <b>Internal API</b> document for details on how this method should be invoked.\r
158          */\r
159         @Override\r
160         public void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
161                 setIpAndFqdnForEelf("doDelete");\r
162                 eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_FEEDID, req.getHeader(BEHALF_HEADER),getIdFromPath(req)+"");\r
163                 EventLogRecord elr = new EventLogRecord(req);\r
164                 if (!isAuthorizedForInternal(req)) {\r
165                         elr.setMessage("Unauthorized.");\r
166                         elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
167                         eventlogger.info(elr);\r
168                         resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthorized.");\r
169                         return;\r
170                 }\r
171 \r
172                 String path = req.getPathInfo();\r
173                 if (path.startsWith("/api/")) {\r
174                         if (isProxyOK(req) && isProxyServer()) {\r
175                                 super.doDelete(req, resp);\r
176                                 return;\r
177                         }\r
178                         String key = path.substring(5);\r
179                         if (key.length() > 0) {\r
180                                 Parameters param = Parameters.getParameter(key);\r
181                                 if (param != null) {\r
182                                         if (doDelete(param)) {\r
183                                                 elr.setResult(HttpServletResponse.SC_OK);\r
184                                                 eventlogger.info(elr);\r
185                                                 resp.setStatus(HttpServletResponse.SC_OK);\r
186                                                 provisioningDataChanged();\r
187                                                 provisioningParametersChanged();\r
188                                         } else {\r
189                                                 // Something went wrong with the DELETE\r
190                                                 elr.setResult(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\r
191                                                 eventlogger.info(elr);\r
192                                                 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DB_PROBLEM_MSG);\r
193                                         }\r
194                                         return;\r
195                                 }\r
196                         }\r
197                 }\r
198                 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Bad URL.");\r
199         }\r
200         /**\r
201          * Get some information (such as a parameter) underneath the /internal/ namespace.\r
202          * See the <b>Internal API</b> document for details on how this method should be invoked.\r
203          */\r
204         @Override\r
205         public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
206                 setIpAndFqdnForEelf("doGet");\r
207                 eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_FEEDID, req.getHeader(BEHALF_HEADER),getIdFromPath(req)+"");\r
208                 String path = req.getPathInfo();\r
209                 if (path.equals("/halt") && !req.isSecure()) {\r
210                         // request to halt the server - can ONLY come from localhost\r
211                         String remote = req.getRemoteAddr();\r
212                         if (remote.equals("127.0.0.1")) {\r
213                                 intlogger.info("PROV0009 Request to HALT received.");\r
214                                 resp.setStatus(HttpServletResponse.SC_OK);\r
215                                 Main.shutdown();\r
216                         } else {\r
217                                 intlogger.info("PROV0010 Disallowed request to HALT received from "+remote);\r
218                                 resp.setStatus(HttpServletResponse.SC_FORBIDDEN);\r
219                         }\r
220                         return;\r
221                 }\r
222 \r
223                 EventLogRecord elr = new EventLogRecord(req);\r
224                 if (!isAuthorizedForInternal(req)) {\r
225                         elr.setMessage("Unauthorized.");\r
226                         elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
227                         eventlogger.info(elr);\r
228                         resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthorized.");\r
229                         return;\r
230                 }\r
231                 if (path.equals("/fetchProv") && !req.isSecure()) {\r
232                         // if request came from active_pod or standby_pod and it is not us, reload prov data\r
233                         SynchronizerTask s = SynchronizerTask.getSynchronizer();\r
234                         s.doFetch();\r
235                         resp.setStatus(HttpServletResponse.SC_OK);\r
236                         return;\r
237                 }\r
238                 if (path.equals("/prov")) {\r
239                         if (isProxyOK(req) && isProxyServer()) {\r
240                                 if (super.doGetWithFallback(req, resp))\r
241                                         return;\r
242                                 // fall back to returning the local data if the remote is unreachable\r
243                                 intlogger.info("Active server unavailable; falling back to local copy.");\r
244                         }\r
245                         Poker p = Poker.getPoker();\r
246                         resp.setStatus(HttpServletResponse.SC_OK);\r
247                         resp.setContentType(PROVFULL_CONTENT_TYPE2);\r
248                         resp.getOutputStream().print(p.getProvisioningString());\r
249                         return;\r
250                 }\r
251                 if (path.equals("/logs") || path.equals("/logs/")) {\r
252                         resp.setStatus(HttpServletResponse.SC_OK);\r
253                         resp.setContentType("application/json");\r
254                         resp.getOutputStream().print(generateLogfileList().toString());\r
255                         return;\r
256                 }\r
257                 if (path.startsWith("/logs/")) {\r
258                         Properties p = (new DB()).getProperties();\r
259                         String logdir = p.getProperty("com.att.research.datarouter.provserver.accesslog.dir");\r
260                         String logfile = path.substring(6);\r
261                         if (logdir != null && logfile != null && logfile.indexOf('/') < 0) {\r
262                                 File log = new File(logdir + "/" + logfile);\r
263                                 if (log.exists() && log.isFile()) {\r
264                                         resp.setStatus(HttpServletResponse.SC_OK);\r
265                                         resp.setContentType("text/plain");\r
266                                         Path logpath = Paths.get(log.getAbsolutePath());\r
267                                         Files.copy(logpath, resp.getOutputStream());\r
268                                         return;\r
269                                 }\r
270                         }\r
271                         resp.sendError(HttpServletResponse.SC_NO_CONTENT, "No file.");\r
272                         return;\r
273                 }\r
274                 if (path.startsWith("/api/")) {\r
275                         if (isProxyOK(req) && isProxyServer()) {\r
276                                 super.doGet(req, resp);\r
277                                 return;\r
278                         }\r
279                         String key = path.substring(5);\r
280                         if (key.length() > 0) {\r
281                                 Parameters param = Parameters.getParameter(key);\r
282                                 if (param != null) {\r
283                                         resp.setStatus(HttpServletResponse.SC_OK);\r
284                                         resp.setContentType("text/plain");\r
285                                         resp.getOutputStream().print(param.getValue() + "\n");\r
286                                         return;\r
287                                 }\r
288                         }\r
289                 }\r
290                 if (path.equals("/drlogs") || path.equals("/drlogs/")) {\r
291                         // Special POD <=> POD API to determine what log file records are loaded here\r
292                         LogfileLoader lfl = LogfileLoader.getLoader();\r
293                         resp.setStatus(HttpServletResponse.SC_OK);\r
294                         resp.setContentType("text/plain");\r
295                         resp.getOutputStream().print(lfl.getBitSet().toString());\r
296                         return;\r
297                 }\r
298                 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Bad URL.");\r
299         }\r
300         /**\r
301          * Modify a parameter at the address /internal/api/&lt;parameter&gt;.\r
302          * See the <b>Internal API</b> document for details on how this method should be invoked.\r
303          */\r
304         @Override\r
305         public void doPut(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
306                 setIpAndFqdnForEelf("doPut");\r
307                 eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_FEEDID, req.getHeader(BEHALF_HEADER),getIdFromPath(req)+"");\r
308                 EventLogRecord elr = new EventLogRecord(req);\r
309                 if (!isAuthorizedForInternal(req)) {\r
310                         elr.setMessage("Unauthorized.");\r
311                         elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
312                         eventlogger.info(elr);\r
313                         resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthorized.");\r
314                         return;\r
315                 }\r
316                 String path = req.getPathInfo();\r
317                 if (path.startsWith("/api/")) {\r
318                         if (isProxyOK(req) && isProxyServer()) {\r
319                                 super.doPut(req, resp);\r
320                                 return;\r
321                         }\r
322                         String key = path.substring(5);\r
323                         if (key.length() > 0) {\r
324                                 Parameters param = Parameters.getParameter(key);\r
325                                 if (param != null) {\r
326                                         String t = catValues(req.getParameterValues("val"));\r
327                                         param.setValue(t);\r
328                                         if (doUpdate(param)) {\r
329                                                 elr.setResult(HttpServletResponse.SC_OK);\r
330                                                 eventlogger.info(elr);\r
331                                                 resp.setStatus(HttpServletResponse.SC_OK);\r
332                                                 provisioningDataChanged();\r
333                                                 provisioningParametersChanged();\r
334                                         } else {\r
335                                                 // Something went wrong with the UPDATE\r
336                                                 elr.setResult(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\r
337                                                 eventlogger.info(elr);\r
338                                                 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DB_PROBLEM_MSG);\r
339                                         }\r
340                                         return;\r
341                                 }\r
342                         }\r
343                 }\r
344                 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Bad URL.");\r
345         }\r
346         /**\r
347          * Create some new information (such as a parameter or log entries) underneath the /internal/ namespace.\r
348          * See the <b>Internal API</b> document for details on how this method should be invoked.\r
349          */\r
350         @SuppressWarnings("resource")\r
351         @Override\r
352         public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
353                 setIpAndFqdnForEelf("doPost");\r
354                 eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF, req.getHeader(BEHALF_HEADER));\r
355                 EventLogRecord elr = new EventLogRecord(req);\r
356                 if (!isAuthorizedForInternal(req)) {\r
357                         elr.setMessage("Unauthorized.");\r
358                         elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
359                         eventlogger.info(elr);\r
360                         resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthorized.");\r
361                         return;\r
362                 }\r
363 \r
364                 String path = req.getPathInfo();\r
365                 if (path.startsWith("/api/")) {\r
366                         if (isProxyOK(req) && isProxyServer()) {\r
367                                 super.doPost(req, resp);\r
368                                 return;\r
369                         }\r
370                         String key = path.substring(5);\r
371                         if (key.length() > 0) {\r
372                                 Parameters param = Parameters.getParameter(key);\r
373                                 if (param == null) {\r
374                                         String t = catValues(req.getParameterValues("val"));\r
375                                         param = new Parameters(key, t);\r
376                                         if (doInsert(param)) {\r
377                                                 elr.setResult(HttpServletResponse.SC_OK);\r
378                                                 eventlogger.info(elr);\r
379                                                 resp.setStatus(HttpServletResponse.SC_OK);\r
380                                                 provisioningDataChanged();\r
381                                                 provisioningParametersChanged();\r
382                                         } else {\r
383                                                 // Something went wrong with the INSERT\r
384                                                 elr.setResult(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\r
385                                                 eventlogger.info(elr);\r
386                                                 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DB_PROBLEM_MSG);\r
387                                         }\r
388                                         return;\r
389                                 }\r
390                         }\r
391                 }\r
392 \r
393                 if (path.equals("/logs") || path.equals("/logs/")) {\r
394                         String ctype = req.getHeader("Content-Type");\r
395                         if (ctype == null || !ctype.equals("text/plain")) {\r
396                                 elr.setResult(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);\r
397                                 elr.setMessage("Bad media type: "+ctype);\r
398                                 resp.setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);\r
399                                 eventlogger.info(elr);\r
400                                 return;\r
401                         }\r
402                         String spooldir = (new DB()).getProperties().getProperty("com.att.research.datarouter.provserver.spooldir");\r
403                         String spoolname = String.format("%d-%d-", System.currentTimeMillis(), Thread.currentThread().getId());\r
404                         synchronized (logseq) {\r
405                                 // perhaps unnecessary, but it helps make the name unique\r
406                                 spoolname += logseq.toString();\r
407                                 logseq++;\r
408                         }\r
409                         String encoding = req.getHeader("Content-Encoding");\r
410                         if (encoding != null) {\r
411                                 if (encoding.trim().equals("gzip")) {\r
412                                         spoolname += ".gz";\r
413                                 } else {\r
414                                         elr.setResult(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);\r
415                                         resp.setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);\r
416                                         eventlogger.info(elr);\r
417                                         return;\r
418                                 }\r
419                         }\r
420                         // Determine space available -- available space must be at least 5%\r
421                         FileSystem fs = (Paths.get(spooldir)).getFileSystem();\r
422                         long total = 0;\r
423                         long avail = 0;\r
424                         for (FileStore store: fs.getFileStores()) {\r
425                                 total += store.getTotalSpace();\r
426                                 avail += store.getUsableSpace();\r
427                         }\r
428                         try { fs.close(); } catch (Exception e) { }\r
429                         if (((avail * 100) / total) < 5) {\r
430                                 elr.setResult(HttpServletResponse.SC_SERVICE_UNAVAILABLE);\r
431                                 resp.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);\r
432                                 eventlogger.info(elr);\r
433                                 return;\r
434                         }\r
435                         Path tmppath = Paths.get(spooldir, spoolname);\r
436                         Path donepath = Paths.get(spooldir, "IN."+spoolname);\r
437                         Files.copy(req.getInputStream(), Paths.get(spooldir, spoolname), StandardCopyOption.REPLACE_EXISTING);\r
438                         Files.move(tmppath, donepath, StandardCopyOption.REPLACE_EXISTING);\r
439                         elr.setResult(HttpServletResponse.SC_CREATED);\r
440                         resp.setStatus(HttpServletResponse.SC_CREATED);\r
441                         eventlogger.info(elr);\r
442                         LogfileLoader.getLoader();      // This starts the logfile loader "task"\r
443                         return;\r
444                 }\r
445 \r
446                 if (path.equals("/drlogs") || path.equals("/drlogs/")) {\r
447                         // Receive post request and generate log entries\r
448                         String ctype = req.getHeader("Content-Type");\r
449                         if (ctype == null || !ctype.equals("text/plain")) {\r
450                                 elr.setResult(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);\r
451                                 elr.setMessage("Bad media type: "+ctype);\r
452                                 resp.setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);\r
453                                 eventlogger.info(elr);\r
454                                 return;\r
455                         }\r
456                         InputStream is = req.getInputStream();\r
457                         ByteArrayOutputStream bos = new ByteArrayOutputStream();\r
458                         int ch = 0;\r
459                         while ((ch = is.read()) >= 0)\r
460                                 bos.write(ch);\r
461                         RLEBitSet bs = new RLEBitSet(bos.toString());   // The set of records to retrieve\r
462                         elr.setResult(HttpServletResponse.SC_OK);\r
463                         resp.setStatus(HttpServletResponse.SC_OK);\r
464                         resp.setContentType("text/plain");\r
465                         LogRecord.printLogRecords(resp.getOutputStream(), bs);\r
466                         eventlogger.info(elr);\r
467                         return;\r
468                 }\r
469 \r
470                 elr.setResult(HttpServletResponse.SC_NOT_FOUND);\r
471                 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Bad URL.");\r
472                 eventlogger.info(elr);\r
473         }\r
474 \r
475         private String catValues(String[] v) {\r
476                 StringBuilder sb = new StringBuilder();\r
477                 if (v != null) {\r
478                         String pfx = "";\r
479                         for (String s : v) {\r
480                                 sb.append(pfx);\r
481                                 sb.append(s);\r
482                                 pfx = "|";\r
483                         }\r
484                 }\r
485                 return sb.toString();\r
486         }\r
487         private JSONArray generateLogfileList() {\r
488                 JSONArray ja = new JSONArray();\r
489                 Properties p = (new DB()).getProperties();\r
490                 String s = p.getProperty("com.att.research.datarouter.provserver.accesslog.dir");\r
491                 if (s != null) {\r
492                         String[] dirs = s.split(",");\r
493                         for (String dir : dirs) {\r
494                                 File f = new File(dir);\r
495                                 String[] list = f.list();\r
496                                 if (list != null) {\r
497                                         for (String s2 : list) {\r
498                                                 if (!s2.startsWith("."))\r
499                                                         ja.put(s2);\r
500                                         }\r
501                                 }\r
502                         }\r
503                 }\r
504                 return ja;\r
505         }\r
506 }\r