datarouter-prov code clean - remove tabs
[dmaap/datarouter.git] / datarouter-prov / src / main / java / org / onap / dmaap / datarouter / provisioning / SubscriptionServlet.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 org.onap.dmaap.datarouter.provisioning;\r
26 \r
27 import java.io.IOException;\r
28 import java.io.InvalidObjectException;\r
29 import java.net.HttpURLConnection;\r
30 import java.net.URL;\r
31 import java.util.List;\r
32 import java.util.Vector;\r
33 \r
34 import javax.servlet.http.HttpServletRequest;\r
35 import javax.servlet.http.HttpServletResponse;\r
36 \r
37 import org.json.JSONException;\r
38 import org.json.JSONObject;\r
39 import org.onap.dmaap.datarouter.authz.AuthorizationResponse;\r
40 import org.onap.dmaap.datarouter.provisioning.beans.EventLogRecord;\r
41 import org.onap.dmaap.datarouter.provisioning.beans.Subscription;\r
42 import org.onap.dmaap.datarouter.provisioning.eelf.EelfMsgs;\r
43 \r
44 import com.att.eelf.configuration.EELFLogger;\r
45 import com.att.eelf.configuration.EELFManager;\r
46 \r
47 /**\r
48  * This servlet handles provisioning for the <subscriptionURL> which is generated by the provisioning\r
49  * server to handle the inspection, modification, and deletion of a particular subscription to a feed.\r
50  * It supports DELETE to delete a subscription, GET to retrieve information about the subscription,\r
51  * and PUT to modify the subscription.  In DR 3.0, POST is also supported in order to reset the subscription\r
52  * timers for individual subscriptions.\r
53  *\r
54  * @author Robert Eby\r
55  * @version $Id$\r
56  */\r
57 @SuppressWarnings("serial")\r
58 public class SubscriptionServlet extends ProxyServlet {\r
59     public static final String SUBCNTRL_CONTENT_TYPE = "application/vnd.att-dr.subscription-control";\r
60     //Adding EELF Logger Rally:US664892\r
61     private static EELFLogger eelflogger = EELFManager.getInstance().getLogger("org.onap.dmaap.datarouter.provisioning.SubscriptionServlet");\r
62 \r
63     /**\r
64      * DELETE on the <subscriptionUrl> -- delete a subscription.\r
65      * See the <i>Deleting a Subscription</i> section in the <b>Provisioning API</b>\r
66      * document for details on how this method should be invoked.\r
67      */\r
68     @Override\r
69     public void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
70         setIpAndFqdnForEelf("doDelete");\r
71         eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_SUBID, req.getHeader(BEHALF_HEADER),getIdFromPath(req)+"");\r
72         EventLogRecord elr = new EventLogRecord(req);\r
73         String message = isAuthorizedForProvisioning(req);\r
74         if (message != null) {\r
75             elr.setMessage(message);\r
76             elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
77             eventlogger.info(elr);\r
78             resp.sendError(HttpServletResponse.SC_FORBIDDEN, message);\r
79             return;\r
80         }\r
81         if (isProxyServer()) {\r
82             super.doDelete(req, resp);\r
83             return;\r
84         }\r
85         String bhdr = req.getHeader(BEHALF_HEADER);\r
86         if (bhdr == null) {\r
87             message = "Missing "+BEHALF_HEADER+" header.";\r
88             elr.setMessage(message);\r
89             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);\r
90             eventlogger.info(elr);\r
91             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);\r
92             return;\r
93         }\r
94         int subid = getIdFromPath(req);\r
95         if (subid < 0) {\r
96             message = "Missing or bad subscription number.";\r
97             elr.setMessage(message);\r
98             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);\r
99             eventlogger.info(elr);\r
100             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);\r
101             return;\r
102         }\r
103         Subscription sub = Subscription.getSubscriptionById(subid);\r
104         if (sub == null) {\r
105             message = "Missing or bad subscription number.";\r
106             elr.setMessage(message);\r
107             elr.setResult(HttpServletResponse.SC_NOT_FOUND);\r
108             eventlogger.info(elr);\r
109             resp.sendError(HttpServletResponse.SC_NOT_FOUND, message);\r
110             return;\r
111         }\r
112         // Check with the Authorizer\r
113         AuthorizationResponse aresp = authz.decide(req);\r
114         if (! aresp.isAuthorized()) {\r
115             message = "Policy Engine disallows access.";\r
116             elr.setMessage(message);\r
117             elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
118             eventlogger.info(elr);\r
119             resp.sendError(HttpServletResponse.SC_FORBIDDEN, message);\r
120             return;\r
121         }\r
122 \r
123         // Delete Subscription\r
124         if (doDelete(sub)) {\r
125             active_subs--;\r
126             // send response\r
127             elr.setResult(HttpServletResponse.SC_NO_CONTENT);\r
128             eventlogger.info(elr);\r
129             resp.setStatus(HttpServletResponse.SC_NO_CONTENT);\r
130             provisioningDataChanged();\r
131         } else {\r
132             // Something went wrong with the DELETE\r
133             elr.setResult(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\r
134             eventlogger.info(elr);\r
135             resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DB_PROBLEM_MSG);\r
136         }\r
137     }\r
138     /**\r
139      * GET on the &lt;subscriptionUrl&gt; -- get information about a subscription.\r
140      * See the <i>Retreiving Information about a Subscription</i> section in the <b>Provisioning API</b>\r
141      * document for details on how this method should be invoked.\r
142      */\r
143     @Override\r
144     public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
145         setIpAndFqdnForEelf("doGet");\r
146         eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_SUBID, req.getHeader(BEHALF_HEADER),getIdFromPath(req)+"");\r
147         EventLogRecord elr = new EventLogRecord(req);\r
148         String message = isAuthorizedForProvisioning(req);\r
149         if (message != null) {\r
150             elr.setMessage(message);\r
151             elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
152             eventlogger.info(elr);\r
153             resp.sendError(HttpServletResponse.SC_FORBIDDEN, message);\r
154             return;\r
155         }\r
156         if (isProxyServer()) {\r
157             super.doGet(req, resp);\r
158             return;\r
159         }\r
160         String bhdr = req.getHeader(BEHALF_HEADER);\r
161         if (bhdr == null) {\r
162             message = "Missing "+BEHALF_HEADER+" header.";\r
163             elr.setMessage(message);\r
164             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);\r
165             eventlogger.info(elr);\r
166             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);\r
167             return;\r
168         }\r
169         int subid = getIdFromPath(req);\r
170         if (subid < 0) {\r
171             message = "Missing or bad subscription number.";\r
172             elr.setMessage(message);\r
173             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);\r
174             eventlogger.info(elr);\r
175             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);\r
176             return;\r
177         }\r
178         Subscription sub = Subscription.getSubscriptionById(subid);\r
179         if (sub == null) {\r
180             message = "Missing or bad subscription number.";\r
181             elr.setMessage(message);\r
182             elr.setResult(HttpServletResponse.SC_NOT_FOUND);\r
183             eventlogger.info(elr);\r
184             resp.sendError(HttpServletResponse.SC_NOT_FOUND, message);\r
185             return;\r
186         }\r
187         // Check with the Authorizer\r
188         AuthorizationResponse aresp = authz.decide(req);\r
189         if (! aresp.isAuthorized()) {\r
190             message = "Policy Engine disallows access.";\r
191             elr.setMessage(message);\r
192             elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
193             eventlogger.info(elr);\r
194             resp.sendError(HttpServletResponse.SC_FORBIDDEN, message);\r
195             return;\r
196         }\r
197 \r
198         // send response\r
199         elr.setResult(HttpServletResponse.SC_OK);\r
200         eventlogger.info(elr);\r
201         resp.setStatus(HttpServletResponse.SC_OK);\r
202         resp.setContentType(SUBFULL_CONTENT_TYPE);\r
203         resp.getOutputStream().print(sub.asJSONObject(true).toString());\r
204     }\r
205     /**\r
206      * PUT on the &lt;subscriptionUrl&gt; -- modify a subscription.\r
207      * See the <i>Modifying a Subscription</i> section in the <b>Provisioning API</b>\r
208      * document for details on how this method should be invoked.\r
209      */\r
210     @Override\r
211     public void doPut(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
212         setIpAndFqdnForEelf("doPut");\r
213         eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_SUBID, req.getHeader(BEHALF_HEADER),getIdFromPath(req)+"");\r
214         EventLogRecord elr = new EventLogRecord(req);\r
215         String message = isAuthorizedForProvisioning(req);\r
216         if (message != null) {\r
217             elr.setMessage(message);\r
218             elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
219             eventlogger.info(elr);\r
220             resp.sendError(HttpServletResponse.SC_FORBIDDEN, message);\r
221             return;\r
222         }\r
223         if (isProxyServer()) {\r
224             super.doPut(req, resp);\r
225             return;\r
226         }\r
227         String bhdr = req.getHeader(BEHALF_HEADER);\r
228         if (bhdr == null) {\r
229             message = "Missing "+BEHALF_HEADER+" header.";\r
230             elr.setMessage(message);\r
231             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);\r
232             eventlogger.info(elr);\r
233             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);\r
234             return;\r
235         }\r
236         int subid = getIdFromPath(req);\r
237         if (subid < 0) {\r
238             message = "Missing or bad subscription number.";\r
239             elr.setMessage(message);\r
240             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);\r
241             eventlogger.info(elr);\r
242             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);\r
243             return;\r
244         }\r
245         Subscription oldsub = Subscription.getSubscriptionById(subid);\r
246         if (oldsub == null) {\r
247             message = "Missing or bad subscription number.";\r
248             elr.setMessage(message);\r
249             elr.setResult(HttpServletResponse.SC_NOT_FOUND);\r
250             eventlogger.info(elr);\r
251             resp.sendError(HttpServletResponse.SC_NOT_FOUND, message);\r
252             return;\r
253         }\r
254         // Check with the Authorizer\r
255         AuthorizationResponse aresp = authz.decide(req);\r
256         if (! aresp.isAuthorized()) {\r
257             message = "Policy Engine disallows access.";\r
258             elr.setMessage(message);\r
259             elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
260             eventlogger.info(elr);\r
261             resp.sendError(HttpServletResponse.SC_FORBIDDEN, message);\r
262             return;\r
263         }\r
264         // check content type is SUB_CONTENT_TYPE, version 1.0\r
265         ContentHeader ch = getContentHeader(req);\r
266         String ver = ch.getAttribute("version");\r
267         if (!ch.getType().equals(SUB_BASECONTENT_TYPE) || !(ver.equals("1.0") || ver.equals("2.0"))) {\r
268             message = "Incorrect content-type";\r
269             elr.setMessage(message);\r
270             elr.setResult(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);\r
271             eventlogger.info(elr);\r
272             resp.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, message);\r
273             return;\r
274         }\r
275         JSONObject jo = getJSONfromInput(req);\r
276         if (jo == null) {\r
277             message = "Badly formed JSON";\r
278             elr.setMessage(message);\r
279             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);\r
280             eventlogger.info(elr);\r
281             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);\r
282             return;\r
283         }\r
284         if (intlogger.isDebugEnabled())\r
285             intlogger.debug(jo.toString());\r
286         Subscription sub = null;\r
287         try {\r
288             sub = new Subscription(jo);\r
289         } catch (InvalidObjectException e) {\r
290             message = e.getMessage();\r
291             elr.setMessage(message);\r
292             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);\r
293             eventlogger.info(elr);\r
294             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);\r
295             return;\r
296         }\r
297         sub.setSubid(oldsub.getSubid());\r
298         sub.setFeedid(oldsub.getFeedid());\r
299         sub.setSubscriber(bhdr);    // set from X-ATT-DR-ON-BEHALF-OF header\r
300 \r
301         String subjectgroup = (req.getHeader("X-ATT-DR-ON-BEHALF-OF-GROUP")); //Adding for group feature:Rally US708115\r
302         if (!oldsub.getSubscriber().equals(sub.getSubscriber()) && subjectgroup == null) {\r
303             message = "This subscriber must be modified by the same subscriber that created it.";\r
304             elr.setMessage(message);\r
305             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);\r
306             eventlogger.info(elr);\r
307             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);\r
308             return;\r
309         }\r
310 \r
311         // Update SUBSCRIPTIONS table entries\r
312         if (doUpdate(sub)) {\r
313             // send response\r
314             elr.setResult(HttpServletResponse.SC_OK);\r
315             eventlogger.info(elr);\r
316             resp.setStatus(HttpServletResponse.SC_OK);\r
317             resp.setContentType(SUBFULL_CONTENT_TYPE);\r
318             resp.getOutputStream().print(sub.asLimitedJSONObject().toString());\r
319 \r
320             /**Change Owner ship of Subscriber     Adding for group feature:Rally US708115*/\r
321             if (jo.has("changeowner") && subjectgroup != null) {\r
322                 Boolean changeowner = (Boolean) jo.get("changeowner");\r
323                 if (changeowner != null && changeowner.equals(true)) {\r
324                     sub.setSubscriber(req.getHeader(BEHALF_HEADER));\r
325                     sub.changeOwnerShip();\r
326                 }\r
327             }\r
328             /***End of change ownership*/\r
329 \r
330             provisioningDataChanged();\r
331         } else {\r
332             // Something went wrong with the UPDATE\r
333             elr.setResult(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\r
334             eventlogger.info(elr);\r
335             resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DB_PROBLEM_MSG);\r
336         }\r
337     }\r
338     /**\r
339      * POST on the &lt;subscriptionUrl&gt; -- control a subscription.\r
340      * See the <i>Resetting a Subscription's Retry Schedule</i> section in the <b>Provisioning API</b>\r
341      * document for details on how this method should be invoked.\r
342      */\r
343     @Override\r
344     public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {\r
345 // OLD pre-3.0 code\r
346 //        String message = "POST not allowed for the subscriptionURL.";\r
347 //        EventLogRecord elr = new EventLogRecord(req);\r
348 //        elr.setMessage(message);\r
349 //        elr.setResult(HttpServletResponse.SC_METHOD_NOT_ALLOWED);\r
350 //        eventlogger.info(elr);\r
351 //        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, message);\r
352 \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         String message = isAuthorizedForProvisioning(req);\r
357         if (message != null) {\r
358             elr.setMessage(message);\r
359             elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
360             eventlogger.info(elr);\r
361             resp.sendError(HttpServletResponse.SC_FORBIDDEN, message);\r
362             return;\r
363         }\r
364         if (isProxyServer()) {\r
365             super.doPost(req, resp);\r
366             return;\r
367         }\r
368         String bhdr = req.getHeader(BEHALF_HEADER);\r
369         if (bhdr == null) {\r
370             message = "Missing "+BEHALF_HEADER+" header.";\r
371             elr.setMessage(message);\r
372             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);\r
373             eventlogger.info(elr);\r
374             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);\r
375             return;\r
376         }\r
377         final int subid = getIdFromPath(req);\r
378         if (subid < 0 || Subscription.getSubscriptionById(subid) == null) {\r
379             message = "Missing or bad subscription number.";\r
380             elr.setMessage(message);\r
381             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);\r
382             eventlogger.info(elr);\r
383             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);\r
384             return;\r
385         }\r
386         // check content type is SUBCNTRL_CONTENT_TYPE, version 1.0\r
387         ContentHeader ch = getContentHeader(req);\r
388         String ver = ch.getAttribute("version");\r
389         if (!ch.getType().equals(SUBCNTRL_CONTENT_TYPE) || !ver.equals("1.0")) {\r
390             message = "Incorrect content-type";\r
391             elr.setMessage(message);\r
392             elr.setResult(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);\r
393             eventlogger.info(elr);\r
394             resp.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, message);\r
395             return;\r
396         }\r
397         // Check with the Authorizer\r
398         AuthorizationResponse aresp = authz.decide(req);\r
399         if (! aresp.isAuthorized()) {\r
400             message = "Policy Engine disallows access.";\r
401             elr.setMessage(message);\r
402             elr.setResult(HttpServletResponse.SC_FORBIDDEN);\r
403             eventlogger.info(elr);\r
404             resp.sendError(HttpServletResponse.SC_FORBIDDEN, message);\r
405             return;\r
406         }\r
407         JSONObject jo = getJSONfromInput(req);\r
408         if (jo == null) {\r
409             message = "Badly formed JSON";\r
410             elr.setMessage(message);\r
411             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);\r
412             eventlogger.info(elr);\r
413             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);\r
414             return;\r
415         }\r
416         try {\r
417             // Only the active POD sends notifications\r
418             boolean active = SynchronizerTask.getSynchronizer().isActive();\r
419             boolean b = jo.getBoolean("failed");\r
420             if (active && !b) {\r
421                 // Notify all nodes to reset the subscription\r
422                 SubscriberNotifyThread t = new SubscriberNotifyThread();\r
423                 t.resetSubscription(subid);\r
424                 t.start();\r
425             }\r
426             // send response\r
427             elr.setResult(HttpServletResponse.SC_ACCEPTED);\r
428             eventlogger.info(elr);\r
429             resp.setStatus(HttpServletResponse.SC_ACCEPTED);\r
430         } catch (JSONException e) {\r
431             message = "Badly formed JSON";\r
432             elr.setMessage(message);\r
433             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);\r
434             eventlogger.info(elr);\r
435             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);\r
436         }\r
437     }\r
438 \r
439     /**\r
440      * A Thread class used to serially send reset notifications to all nodes in the DR network,\r
441      * when a POST is received for a subscription.\r
442      */\r
443     public class SubscriberNotifyThread extends Thread {\r
444         public static final String URL_TEMPLATE = "http://%s/internal/resetSubscription/%d";\r
445         private List<String> urls = new Vector<String>();\r
446 \r
447         public SubscriberNotifyThread() {\r
448             setName("SubscriberNotifyThread");\r
449         }\r
450         public void resetSubscription(int subid) {\r
451             for (String nodename : BaseServlet.getNodes()) {\r
452                 String u = String.format(URL_TEMPLATE, nodename, subid);\r
453                 urls.add(u);\r
454             }\r
455         }\r
456         public void run() {\r
457             try {\r
458                 while (!urls.isEmpty()) {\r
459                     String u = urls.remove(0);\r
460                     try {\r
461                         URL url = new URL(u);\r
462                         HttpURLConnection conn = (HttpURLConnection) url.openConnection();\r
463                         conn.connect();\r
464                         conn.getContentLength();    // Force the GET through\r
465                         conn.disconnect();\r
466                     } catch (IOException e) {\r
467                         intlogger.info("IOException Error accessing URL: "+u+": " + e.getMessage());\r
468                     }\r
469                 }\r
470             } catch (Exception e) {\r
471                 intlogger.warn("Caught exception in SubscriberNotifyThread: "+e);\r
472                 e.printStackTrace();\r
473             }\r
474         }\r
475     }\r
476 }\r