datarouter-prov code clean - remove tabs
[dmaap/datarouter.git] / datarouter-prov / src / main / java / org / onap / dmaap / datarouter / provisioning / beans / IngressRoute.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.beans;\r
26 \r
27 import java.net.InetAddress;\r
28 import java.net.UnknownHostException;\r
29 import java.sql.Connection;\r
30 import java.sql.PreparedStatement;\r
31 import java.sql.ResultSet;\r
32 import java.sql.SQLException;\r
33 import java.sql.Statement;\r
34 import java.util.ArrayList;\r
35 import java.util.Collection;\r
36 import java.util.Set;\r
37 import java.util.SortedSet;\r
38 import java.util.TreeSet;\r
39 \r
40 import javax.servlet.http.HttpServletRequest;\r
41 \r
42 import org.apache.commons.codec.binary.Base64;\r
43 import org.apache.log4j.Logger;\r
44 import org.json.JSONArray;\r
45 import org.json.JSONObject;\r
46 import org.onap.dmaap.datarouter.provisioning.utils.DB;\r
47 \r
48 /**\r
49  * The representation of one route in the Ingress Route Table.\r
50  *\r
51  * @author Robert P. Eby\r
52  * @version $Id: IngressRoute.java,v 1.3 2013/12/16 20:30:23 eby Exp $\r
53  */\r
54 public class IngressRoute extends NodeClass implements Comparable<IngressRoute> {\r
55     private static Logger intlogger = Logger.getLogger("org.onap.dmaap.datarouter.provisioning.internal");\r
56     private final int seq;\r
57     private final int feedid;\r
58     private final String userid;\r
59     private final String subnet;\r
60     private int nodelist;\r
61     private SortedSet<String> nodes;\r
62 \r
63     /**\r
64      * Get all IngressRoutes in the database, sorted in order according to their sequence field.\r
65      *\r
66      * @return a sorted set of IngressRoutes\r
67      */\r
68     public static SortedSet<IngressRoute> getAllIngressRoutes() {\r
69         return getAllIngressRoutesForSQL("select SEQUENCE, FEEDID, USERID, SUBNET, NODESET from INGRESS_ROUTES");\r
70     }\r
71 \r
72     /**\r
73      * Get all IngressRoutes in the database with a particular sequence number.\r
74      *\r
75      * @param seq the sequence number\r
76      * @return a set of IngressRoutes\r
77      */\r
78     public static Set<IngressRoute> getIngressRoutesForSeq(int seq) {\r
79         return getAllIngressRoutesForSQL("select SEQUENCE, FEEDID, USERID, SUBNET, NODESET from INGRESS_ROUTES where SEQUENCE = " + seq);\r
80     }\r
81 \r
82     private static SortedSet<IngressRoute> getAllIngressRoutesForSQL(String sql) {\r
83         SortedSet<IngressRoute> set = new TreeSet<IngressRoute>();\r
84         try {\r
85             DB db = new DB();\r
86             @SuppressWarnings("resource")\r
87             Connection conn = db.getConnection();\r
88             Statement stmt = conn.createStatement();\r
89             ResultSet rs = stmt.executeQuery(sql);\r
90             while (rs.next()) {\r
91                 int seq = rs.getInt("SEQUENCE");\r
92                 int feedid = rs.getInt("FEEDID");\r
93                 String user = rs.getString("USERID");\r
94                 String subnet = rs.getString("SUBNET");\r
95                 int nodeset = rs.getInt("NODESET");\r
96                 set.add(new IngressRoute(seq, feedid, user, subnet, nodeset));\r
97             }\r
98             rs.close();\r
99             stmt.close();\r
100             db.release(conn);\r
101         } catch (SQLException e) {\r
102             e.printStackTrace();\r
103         }\r
104         return set;\r
105     }\r
106 \r
107     /**\r
108      * Get the maximum node set ID in use in the DB.\r
109      *\r
110      * @return the integer value of the maximum\r
111      */\r
112     public static int getMaxNodeSetID() {\r
113         return getMax("select max(SETID) as MAX from NODESETS");\r
114     }\r
115 \r
116     /**\r
117      * Get the maximum node sequence number in use in the DB.\r
118      *\r
119      * @return the integer value of the maximum\r
120      */\r
121     public static int getMaxSequence() {\r
122         return getMax("select max(SEQUENCE) as MAX from INGRESS_ROUTES");\r
123     }\r
124 \r
125     private static int getMax(String sql) {\r
126         int rv = 0;\r
127         try {\r
128             DB db = new DB();\r
129             @SuppressWarnings("resource")\r
130             Connection conn = db.getConnection();\r
131             Statement stmt = conn.createStatement();\r
132             ResultSet rs = stmt.executeQuery(sql);\r
133             if (rs.next()) {\r
134                 rv = rs.getInt("MAX");\r
135             }\r
136             rs.close();\r
137             stmt.close();\r
138             db.release(conn);\r
139         } catch (SQLException e) {\r
140             e.printStackTrace();\r
141         }\r
142         return rv;\r
143     }\r
144 \r
145     /**\r
146      * Get an Ingress Route for a particular feed ID, user, and subnet\r
147      *\r
148      * @param feedid the Feed ID to look for\r
149      * @param user   the user name to look for\r
150      * @param subnet the subnet to look for\r
151      * @return the Ingress Route, or null of there is none\r
152      */\r
153     public static IngressRoute getIngressRoute(int feedid, String user, String subnet) {\r
154         IngressRoute v = null;\r
155         PreparedStatement ps = null;\r
156         try {\r
157             DB db = new DB();\r
158             @SuppressWarnings("resource")\r
159             Connection conn = db.getConnection();\r
160             String sql = "select SEQUENCE, NODESET from INGRESS_ROUTES where FEEDID = ? AND USERID = ? and SUBNET = ?";\r
161             ps = conn.prepareStatement(sql);\r
162             ps.setInt(1, feedid);\r
163             ps.setString(2, user);\r
164             ps.setString(3, subnet);\r
165             ResultSet rs = ps.executeQuery();\r
166             if (rs.next()) {\r
167                 int seq = rs.getInt("SEQUENCE");\r
168                 int nodeset = rs.getInt("NODESET");\r
169                 v = new IngressRoute(seq, feedid, user, subnet, nodeset);\r
170             }\r
171             rs.close();\r
172             ps.close();\r
173             db.release(conn);\r
174         } catch (SQLException e) {\r
175             e.printStackTrace();\r
176         } finally {\r
177             try {\r
178                 ps.close();\r
179             } catch (SQLException e) {\r
180                 e.printStackTrace();\r
181             }\r
182         }\r
183         return v;\r
184     }\r
185 \r
186     /**\r
187      * Get a collection of all Ingress Routes with a particular sequence number.\r
188      *\r
189      * @param seq the sequence number to look for\r
190      * @return the collection (may be empty).\r
191      */\r
192     public static Collection<IngressRoute> getIngressRoute(int seq) {\r
193         Collection<IngressRoute> rv = new ArrayList<IngressRoute>();\r
194         PreparedStatement ps = null;\r
195         try {\r
196             DB db = new DB();\r
197             @SuppressWarnings("resource")\r
198             Connection conn = db.getConnection();\r
199             String sql = "select FEEDID, USERID, SUBNET, NODESET from INGRESS_ROUTES where SEQUENCE = ?";\r
200             ps = conn.prepareStatement(sql);\r
201             ps.setInt(1, seq);\r
202             ResultSet rs = ps.executeQuery();\r
203             while (rs.next()) {\r
204                 int feedid = rs.getInt("FEEDID");\r
205                 String user = rs.getString("USERID");\r
206                 String subnet = rs.getString("SUBNET");\r
207                 int nodeset = rs.getInt("NODESET");\r
208                 rv.add(new IngressRoute(seq, feedid, user, subnet, nodeset));\r
209             }\r
210             rs.close();\r
211             ps.close();\r
212             db.release(conn);\r
213         } catch (SQLException e) {\r
214             e.printStackTrace();\r
215         } finally {\r
216             try {\r
217                 ps.close();\r
218             } catch (SQLException e) {\r
219                 e.printStackTrace();\r
220             }\r
221         }\r
222         return rv;\r
223     }\r
224 \r
225     public IngressRoute(int seq, int feedid, String user, String subnet, Collection<String> nodes)\r
226             throws IllegalArgumentException {\r
227         this(seq, feedid, user, subnet);\r
228         this.nodelist = -1;\r
229         this.nodes = new TreeSet<String>(nodes);\r
230     }\r
231 \r
232     public IngressRoute(int seq, int feedid, String user, String subnet, int nodeset)\r
233             throws IllegalArgumentException {\r
234         this(seq, feedid, user, subnet);\r
235         this.nodelist = nodeset;\r
236         this.nodes = new TreeSet<String>(readNodes());\r
237     }\r
238 \r
239     private IngressRoute(int seq, int feedid, String user, String subnet)\r
240             throws IllegalArgumentException {\r
241         this.seq = seq;\r
242         this.feedid = feedid;\r
243         this.userid = (user == null) ? "-" : user;\r
244         this.subnet = (subnet == null) ? "-" : subnet;\r
245         this.nodelist = -1;\r
246         this.nodes = null;\r
247         if (Feed.getFeedById(feedid) == null)\r
248             throw new IllegalArgumentException("No such feed: " + feedid);\r
249         if (!this.subnet.equals("-")) {\r
250             SubnetMatcher sm = new SubnetMatcher(subnet);\r
251             if (!sm.isValid())\r
252                 throw new IllegalArgumentException("Invalid subnet: " + subnet);\r
253         }\r
254     }\r
255 \r
256     public IngressRoute(JSONObject jo) {\r
257         this.seq = jo.optInt("seq");\r
258         this.feedid = jo.optInt("feedid");\r
259         String t = jo.optString("user");\r
260         this.userid = t.equals("") ? "-" : t;\r
261         t = jo.optString("subnet");\r
262         this.subnet = t.equals("") ? "-" : t;\r
263         this.nodelist = -1;\r
264         this.nodes = new TreeSet<String>();\r
265         JSONArray ja = jo.getJSONArray("node");\r
266         for (int i = 0; i < ja.length(); i++)\r
267             this.nodes.add(ja.getString(i));\r
268     }\r
269 \r
270     /**\r
271      * Does this particular IngressRoute match a request, represented by feedid and req?\r
272      * To match, <i>feedid</i> must match the feed ID in the route, the user in the route\r
273      * (if specified) must match the user in the request, and the subnet in the route (if specified)\r
274      * must match the subnet from the request.\r
275      *\r
276      * @param feedid the feedid for this request\r
277      * @param req    the remainder of the request\r
278      * @return true if a match, false otherwise\r
279      */\r
280     public boolean matches(int feedid, HttpServletRequest req) {\r
281         // Check feedid\r
282         if (this.feedid != feedid)\r
283             return false;\r
284 \r
285         // Get user from request and compare\r
286         // Note: we don't check the password; the node will do that\r
287         if (userid.length() > 0 && !userid.equals("-")) {\r
288             String credentials = req.getHeader("Authorization");\r
289             if (credentials == null || !credentials.startsWith("Basic "))\r
290                 return false;\r
291             String t = new String(Base64.decodeBase64(credentials.substring(6)));\r
292             int ix = t.indexOf(':');\r
293             if (ix >= 0)\r
294                 t = t.substring(0, ix);\r
295             if (!t.equals(this.userid))\r
296                 return false;\r
297         }\r
298 \r
299         // If this route has a subnet, match it against the requester's IP addr\r
300         if (subnet.length() > 0 && !subnet.equals("-")) {\r
301             try {\r
302                 InetAddress inet = InetAddress.getByName(req.getRemoteAddr());\r
303                 SubnetMatcher sm = new SubnetMatcher(subnet);\r
304                 return sm.matches(inet.getAddress());\r
305             } catch (UnknownHostException e) {\r
306                 return false;\r
307             }\r
308         }\r
309         return true;\r
310     }\r
311 \r
312     /**\r
313      * Compare IP addresses as byte arrays to a subnet specified as a CIDR.\r
314      * Taken from org.onap.dmaap.datarouter.node.SubnetMatcher and modified somewhat.\r
315      */\r
316     public class SubnetMatcher {\r
317         private byte[] sn;\r
318         private int len;\r
319         private int mask;\r
320         private boolean valid;\r
321 \r
322         /**\r
323          * Construct a subnet matcher given a CIDR\r
324          *\r
325          * @param subnet The CIDR to match\r
326          */\r
327         public SubnetMatcher(String subnet) {\r
328             int i = subnet.lastIndexOf('/');\r
329             if (i == -1) {\r
330                 try {\r
331                     sn = InetAddress.getByName(subnet).getAddress();\r
332                     len = sn.length;\r
333                     valid = true;\r
334                 } catch (UnknownHostException e) {\r
335                     len = 0;\r
336                     valid = false;\r
337                 }\r
338                 mask = 0;\r
339             } else {\r
340                 int n = Integer.parseInt(subnet.substring(i + 1));\r
341                 try {\r
342                     sn = InetAddress.getByName(subnet.substring(0, i)).getAddress();\r
343                     valid = true;\r
344                 } catch (UnknownHostException e) {\r
345                     valid = false;\r
346                 }\r
347                 len = n / 8;\r
348                 mask = ((0xff00) >> (n % 8)) & 0xff;\r
349             }\r
350         }\r
351 \r
352         public boolean isValid() {\r
353             return valid;\r
354         }\r
355 \r
356         /**\r
357          * Is the IP address in the CIDR?\r
358          *\r
359          * @param addr the IP address as bytes in network byte order\r
360          * @return true if the IP address matches.\r
361          */\r
362         public boolean matches(byte[] addr) {\r
363             if (!valid || addr.length != sn.length) {\r
364                 return false;\r
365             }\r
366             for (int i = 0; i < len; i++) {\r
367                 if (addr[i] != sn[i]) {\r
368                     return false;\r
369                 }\r
370             }\r
371             if (mask != 0 && ((addr[len] ^ sn[len]) & mask) != 0) {\r
372                 return false;\r
373             }\r
374             return true;\r
375         }\r
376     }\r
377 \r
378     /**\r
379      * Get the list of node names for this route.\r
380      *\r
381      * @return the list\r
382      */\r
383     public SortedSet<String> getNodes() {\r
384         return this.nodes;\r
385     }\r
386 \r
387     private Collection<String> readNodes() {\r
388         Collection<String> set = new TreeSet<String>();\r
389         PreparedStatement ps = null;\r
390         try {\r
391             DB db = new DB();\r
392             @SuppressWarnings("resource")\r
393             Connection conn = db.getConnection();\r
394             Statement stmt = conn.createStatement();\r
395             String sql = "select NODEID from NODESETS where SETID = ?";\r
396             ps = conn.prepareStatement(sql);\r
397             ps.setInt(1, nodelist);\r
398             ResultSet rs = ps.executeQuery();\r
399             while (rs.next()) {\r
400                 int id = rs.getInt("NODEID");\r
401                 set.add(lookupNodeID(id));\r
402             }\r
403             rs.close();\r
404             stmt.close();\r
405             db.release(conn);\r
406         } catch (SQLException e) {\r
407             e.printStackTrace();\r
408         } finally {\r
409             try {\r
410                 ps.close();\r
411             } catch (SQLException e) {\r
412                 e.printStackTrace();\r
413             }\r
414         }\r
415         return set;\r
416     }\r
417 \r
418     /**\r
419      * Delete the IRT route having this IngressRoutes feed ID, user ID, and subnet from the database.\r
420      *\r
421      * @return true if the delete succeeded\r
422      */\r
423     @Override\r
424     public boolean doDelete(Connection c) {\r
425         boolean rv = true;\r
426         PreparedStatement ps = null;\r
427         try {\r
428             ps = c.prepareStatement("delete from INGRESS_ROUTES where FEEDID = ? and USERID = ? and SUBNET = ?");\r
429             ps.setInt(1, feedid);\r
430             ps.setString(2, userid);\r
431             ps.setString(3, subnet);\r
432             ps.execute();\r
433             ps.close();\r
434 \r
435             ps = c.prepareStatement("delete from NODESETS where SETID = ?");\r
436             ps.setInt(1, nodelist);\r
437             ps.execute();\r
438         } catch (SQLException e) {\r
439             rv = false;\r
440             intlogger.warn("PROV0007 doDelete: " + e.getMessage());\r
441             e.printStackTrace();\r
442         } finally {\r
443             try {\r
444                 ps.close();\r
445             } catch (SQLException e) {\r
446                 e.printStackTrace();\r
447             }\r
448         }\r
449         return rv;\r
450     }\r
451 \r
452     @SuppressWarnings("resource")\r
453     @Override\r
454     public boolean doInsert(Connection c) {\r
455         boolean rv = false;\r
456         PreparedStatement ps = null;\r
457         try {\r
458             // Create the NODESETS rows & set nodelist\r
459             int set = getMaxNodeSetID() + 1;\r
460             this.nodelist = set;\r
461             for (String node : nodes) {\r
462                 int id = lookupNodeName(node);\r
463                 ps = c.prepareStatement("insert into NODESETS (SETID, NODEID) values (?,?)");\r
464                 ps.setInt(1, this.nodelist);\r
465                 ps.setInt(2, id);\r
466                 ps.execute();\r
467                 ps.close();\r
468             }\r
469 \r
470             // Create the INGRESS_ROUTES row\r
471             ps = c.prepareStatement("insert into INGRESS_ROUTES (SEQUENCE, FEEDID, USERID, SUBNET, NODESET) values (?, ?, ?, ?, ?)");\r
472             ps.setInt(1, this.seq);\r
473             ps.setInt(2, this.feedid);\r
474             ps.setString(3, this.userid);\r
475             ps.setString(4, this.subnet);\r
476             ps.setInt(5, this.nodelist);\r
477             ps.execute();\r
478             ps.close();\r
479             rv = true;\r
480         } catch (SQLException e) {\r
481             intlogger.warn("PROV0005 doInsert: " + e.getMessage());\r
482             e.printStackTrace();\r
483         } finally {\r
484             try {\r
485                 ps.close();\r
486             } catch (SQLException e) {\r
487                 e.printStackTrace();\r
488             }\r
489         }\r
490         return rv;\r
491     }\r
492 \r
493     @Override\r
494     public boolean doUpdate(Connection c) {\r
495         return doDelete(c) && doInsert(c);\r
496     }\r
497 \r
498     @Override\r
499     public JSONObject asJSONObject() {\r
500         JSONObject jo = new JSONObject();\r
501         jo.put("feedid", feedid);\r
502         // Note: for user and subnet, null, "", and "-" are equivalent\r
503         if (userid != null && !userid.equals("-") && !userid.equals(""))\r
504             jo.put("user", userid);\r
505         if (subnet != null && !subnet.equals("-") && !subnet.equals(""))\r
506             jo.put("subnet", subnet);\r
507         jo.put("seq", seq);\r
508         jo.put("node", nodes);\r
509         return jo;\r
510     }\r
511 \r
512     @Override\r
513     public String getKey() {\r
514         return String.format("%d/%s/%s/%d", feedid, (userid == null) ? "" : userid, (subnet == null) ? "" : subnet, seq);\r
515     }\r
516 \r
517     @Override\r
518     public int hashCode() {\r
519         return toString().hashCode();\r
520     }\r
521 \r
522     @Override\r
523     public boolean equals(Object obj) {\r
524         try {\r
525             if (!(obj instanceof IngressRoute))\r
526                 return false;\r
527             return this.compareTo((IngressRoute) obj) == 0;\r
528         } catch (NullPointerException e) {\r
529             return false;\r
530         }\r
531     }\r
532 \r
533     @Override\r
534     public int compareTo(IngressRoute in) {\r
535         if (in == null)\r
536             throw new NullPointerException();\r
537         int n = this.feedid - in.feedid;\r
538         if (n != 0)\r
539             return n;\r
540         n = this.seq - in.seq;\r
541         if (n != 0)\r
542             return n;\r
543         n = this.userid.compareTo(in.userid);\r
544         if (n != 0)\r
545             return n;\r
546         n = this.subnet.compareTo(in.subnet);\r
547         if (n != 0)\r
548             return n;\r
549         return this.nodes.equals(in.nodes) ? 0 : 1;\r
550     }\r
551 \r
552     @Override\r
553     public String toString() {\r
554         return String.format("INGRESS: feed=%d, userid=%s, subnet=%s, seq=%d", feedid, (userid == null) ? "" : userid, (subnet == null) ? "" : subnet, seq);\r
555     }\r
556 }\r