[DMAAP-48] Initial code import
[dmaap/datarouter.git] / datarouter-node / src / main / java / com / att / research / datarouter / node / NodeConfig.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.node;\r
26 \r
27 import java.util.*;\r
28 import java.io.*;\r
29 \r
30 /**\r
31  *      Processed configuration for this node.\r
32  *      <p>\r
33  *      The NodeConfig represents a processed configuration from the Data Router\r
34  *      provisioning server.  Each time configuration data is received from the\r
35  *      provisioning server, a new NodeConfig is created and the previous one\r
36  *      discarded.\r
37  */\r
38 public class NodeConfig {\r
39         /**\r
40          *      Raw configuration entry for a data router node\r
41          */\r
42         public static class ProvNode {\r
43                 private String cname;\r
44                 /**\r
45                  *      Construct a node configuration entry.\r
46                  *      @param cname    The cname of the node.\r
47                  */\r
48                 public ProvNode(String cname) {\r
49                         this.cname = cname;\r
50                 }\r
51                 /**\r
52                  *      Get the cname of the node\r
53                  */\r
54                 public String getCName() {\r
55                         return(cname);\r
56                 }\r
57         }\r
58         /**\r
59          *      Raw configuration entry for a provisioning parameter\r
60          */\r
61         public static class ProvParam {\r
62                 private String name;\r
63                 private String value;\r
64                 /**\r
65                  *      Construct a provisioning parameter configuration entry.\r
66                  *      @param  name The name of the parameter.\r
67                  *      @param  value The value of the parameter.\r
68                  */\r
69                 public ProvParam(String name, String value) {\r
70                         this.name = name;\r
71                         this.value = value;\r
72                 }\r
73                 /**\r
74                  *      Get the name of the parameter.\r
75                  */\r
76                 public String getName() {\r
77                         return(name);\r
78                 }\r
79                 /**\r
80                  *      Get the value of the parameter.\r
81                  */\r
82                 public String getValue() {\r
83                         return(value);\r
84                 }\r
85         }\r
86         /**\r
87          *      Raw configuration entry for a data feed.\r
88          */\r
89         public static class ProvFeed {\r
90                 private String id;\r
91                 private String logdata;\r
92                 private String status;\r
93                 /**\r
94                  *      Construct a feed configuration entry.\r
95                  *      @param id       The feed ID of the entry.\r
96                  *      @param logdata  String for log entries about the entry.\r
97                  *      @param status   The reason why this feed cannot be used (Feed has been deleted, Feed has been suspended) or null if it is valid.\r
98                  */\r
99                 public ProvFeed(String id, String logdata, String status) {\r
100                         this.id = id;\r
101                         this.logdata = logdata;\r
102                         this.status = status;\r
103                 }\r
104                 /**\r
105                  *      Get the feed id of the data feed.\r
106                  */\r
107                 public String getId() {\r
108                         return(id);\r
109                 }\r
110                 /**\r
111                  *      Get the log data of the data feed.\r
112                  */\r
113                 public String getLogData() {\r
114                         return(logdata);\r
115                 }\r
116                 /**\r
117                  *      Get the status of the data feed.\r
118                  */\r
119                 public String getStatus() {\r
120                         return(status);\r
121                 }\r
122         }\r
123         /**\r
124          *      Raw configuration entry for a feed user.\r
125          */\r
126         public static class ProvFeedUser        {\r
127                 private String feedid;\r
128                 private String user;\r
129                 private String credentials;\r
130                 /**\r
131                  *      Construct a feed user configuration entry\r
132                  *      @param feedid   The feed id.\r
133                  *      @param user     The user that will publish to the feed.\r
134                  *      @param credentials      The Authorization header the user will use to publish.\r
135                  */\r
136                 public ProvFeedUser(String feedid, String user, String credentials) {\r
137                         this.feedid = feedid;\r
138                         this.user = user;\r
139                         this.credentials = credentials;\r
140                 }\r
141                 /**\r
142                  *      Get the feed id of the feed user.\r
143                  */\r
144                 public String getFeedId() {\r
145                         return(feedid);\r
146                 }\r
147                 /**\r
148                  *      Get the user for the feed user.\r
149                  */\r
150                 public String getUser() {\r
151                         return(user);\r
152                 }\r
153                 /**\r
154                  *      Get the credentials for the feed user.\r
155                  */\r
156                 public String getCredentials() {\r
157                         return(credentials);\r
158                 }\r
159         }\r
160         /**\r
161          *      Raw configuration entry for a feed subnet\r
162          */\r
163         public static class ProvFeedSubnet      {\r
164                 private String feedid;\r
165                 private String cidr;\r
166                 /**\r
167                  *      Construct a feed subnet configuration entry\r
168                  *      @param feedid   The feed ID\r
169                  *      @param cidr     The CIDR allowed to publish to the feed.\r
170                  */\r
171                 public ProvFeedSubnet(String feedid, String cidr) {\r
172                         this.feedid = feedid;\r
173                         this.cidr = cidr;\r
174                 }\r
175                 /**\r
176                  *      Get the feed id of the feed subnet.\r
177                  */\r
178                 public String getFeedId() {\r
179                         return(feedid);\r
180                 }\r
181                 /**\r
182                  *      Get the CIDR of the feed subnet.\r
183                  */\r
184                 public String getCidr() {\r
185                         return(cidr);\r
186                 }\r
187         }\r
188         /**\r
189          *      Raw configuration entry for a subscription\r
190          */\r
191         public static class ProvSubscription    {\r
192                 private String  subid;\r
193                 private String  feedid;\r
194                 private String  url;\r
195                 private String  authuser;\r
196                 private String  credentials;\r
197                 private boolean metaonly;\r
198                 private boolean use100;\r
199                 /**\r
200                  *      Construct a subscription configuration entry\r
201                  *      @param subid    The subscription ID\r
202                  *      @param feedid   The feed ID\r
203                  *      @param url      The base delivery URL (not including the fileid)\r
204                  *      @param authuser The user in the credentials used to deliver\r
205                  *      @param credentials      The credentials used to authenticate to the delivery URL exactly as they go in the Authorization header.\r
206                  *      @param metaonly Is this a meta data only subscription?\r
207                  *      @param use100   Should we send Expect: 100-continue?\r
208                  */\r
209                 public ProvSubscription(String subid, String feedid, String url, String authuser, String credentials, boolean metaonly, boolean use100) {\r
210                         this.subid = subid;\r
211                         this.feedid = feedid;\r
212                         this.url = url;\r
213                         this.authuser = authuser;\r
214                         this.credentials = credentials;\r
215                         this.metaonly = metaonly;\r
216                         this.use100 = use100;\r
217                 }\r
218                 /**\r
219                  *      Get the subscription ID\r
220                  */\r
221                 public String getSubId() {\r
222                         return(subid);\r
223                 }\r
224                 /**\r
225                  *      Get the feed ID\r
226                  */\r
227                 public String getFeedId() {\r
228                         return(feedid);\r
229                 }\r
230                 /**\r
231                  *      Get the delivery URL\r
232                  */\r
233                 public String getURL() {\r
234                         return(url);\r
235                 }\r
236                 /**\r
237                  *      Get the user\r
238                  */\r
239                 public String getAuthUser() {\r
240                         return(authuser);\r
241                 }\r
242                 /**\r
243                  *      Get the delivery credentials\r
244                  */\r
245                 public String getCredentials() {\r
246                         return(credentials);\r
247                 }\r
248                 /**\r
249                  *      Is this a meta data only subscription?\r
250                  */\r
251                 public boolean isMetaDataOnly() {\r
252                         return(metaonly);\r
253                 }\r
254                 /**\r
255                  *      Should we send Expect: 100-continue?\r
256                  */\r
257                 public boolean isUsing100() {\r
258                         return(use100);\r
259                 }\r
260         }\r
261         /**\r
262          *      Raw configuration entry for controlled ingress to the data router node\r
263          */\r
264         public static class ProvForceIngress    {\r
265                 private String feedid;\r
266                 private String subnet;\r
267                 private String user;\r
268                 private String[] nodes;\r
269                 /**\r
270                  *      Construct a forced ingress configuration entry\r
271                  *      @param feedid   The feed ID that this entry applies to\r
272                  *      @param subnet   The CIDR for which publisher IP addresses this entry applies to or "" if it applies to all publisher IP addresses\r
273                  *      @param user     The publishing user this entry applies to or "" if it applies to all publishing users.\r
274                  *      @param nodes    The array of FQDNs of the data router nodes to redirect publication attempts to.\r
275                  */\r
276                 public ProvForceIngress(String feedid, String subnet, String user, String[] nodes) {\r
277                         this.feedid = feedid;\r
278                         this.subnet = subnet;\r
279                         this.user = user;\r
280                         this.nodes = nodes;\r
281                 }\r
282                 /**\r
283                  *      Get the feed ID\r
284                  */\r
285                 public String getFeedId() {\r
286                         return(feedid);\r
287                 }\r
288                 /**\r
289                  *      Get the subnet\r
290                  */\r
291                 public String getSubnet() {\r
292                         return(subnet);\r
293                 }\r
294                 /**\r
295                  *      Get the user\r
296                  */\r
297                 public String getUser() {\r
298                         return(user);\r
299                 }\r
300                 /**\r
301                  *      Get the node\r
302                  */\r
303                 public String[] getNodes() {\r
304                         return(nodes);\r
305                 }\r
306         }\r
307         /**\r
308          *      Raw configuration entry for controlled egress from the data router\r
309          */\r
310         public static class ProvForceEgress     {\r
311                 private String subid;\r
312                 private String node;\r
313                 /**\r
314                  *      Construct a forced egress configuration entry\r
315                  *      @param subid    The subscription ID the subscription with forced egress\r
316                  *      @param node     The node handling deliveries for this subscription\r
317                  */\r
318                 public ProvForceEgress(String subid, String node) {\r
319                         this.subid = subid;\r
320                         this.node = node;\r
321                 }\r
322                 /**\r
323                  *      Get the subscription ID\r
324                  */\r
325                 public String getSubId() {\r
326                         return(subid);\r
327                 }\r
328                 /**\r
329                  *      Get the node\r
330                  */\r
331                 public String getNode() {\r
332                         return(node);\r
333                 }\r
334         }\r
335         /**\r
336          *      Raw configuration entry for routing within the data router network\r
337          */\r
338         public static class ProvHop     {\r
339                 private String  from;\r
340                 private String  to;\r
341                 private String  via;\r
342                 /**\r
343                  *      A human readable description of this entry\r
344                  */\r
345                 public String toString() {\r
346                         return("Hop " + from + "->" + to + " via " + via);\r
347                 }\r
348                 /**\r
349                  *      Construct a hop entry\r
350                  *      @param from     The FQDN of the node with the data to be delivered\r
351                  *      @param to       The FQDN of the node that will deliver to the subscriber\r
352                  *      @param via      The FQDN of the node where the from node should send the data\r
353                  */\r
354                 public ProvHop(String from, String to, String via) {\r
355                         this.from = from;\r
356                         this.to = to;\r
357                         this.via = via;\r
358                 }\r
359                 /**\r
360                  *      Get the from node\r
361                  */\r
362                 public String getFrom() {\r
363                         return(from);\r
364                 }\r
365                 /**\r
366                  *      Get the to node\r
367                  */\r
368                 public String getTo() {\r
369                         return(to);\r
370                 }\r
371                 /**\r
372                  *      Get the next intermediate node\r
373                  */\r
374                 public String getVia() {\r
375                         return(via);\r
376                 }\r
377         }\r
378         private static class Redirection        {\r
379                 public SubnetMatcher snm;\r
380                 public String user;\r
381                 public String[] nodes;\r
382         }\r
383         private static class Feed       {\r
384                 public String   loginfo;\r
385                 public String   status;\r
386                 public SubnetMatcher[] subnets;\r
387                 public Hashtable<String, String> authusers = new Hashtable<String, String>();\r
388                 public Redirection[]    redirections;\r
389                 public Target[] targets;\r
390         }\r
391         private Hashtable<String, String> params = new Hashtable<String, String>();\r
392         private Hashtable<String, Feed> feeds = new Hashtable<String, Feed>();\r
393         private Hashtable<String, DestInfo> nodeinfo = new Hashtable<String, DestInfo>();\r
394         private Hashtable<String, DestInfo> subinfo = new Hashtable<String, DestInfo>();\r
395         private Hashtable<String, IsFrom> nodes = new Hashtable<String, IsFrom>();\r
396         private String  myname;\r
397         private String  myauth;\r
398         private DestInfo[]      alldests;\r
399         private int     rrcntr;\r
400         /**\r
401          *      Process the raw provisioning data to configure this node\r
402          *      @param pd       The parsed provisioning data\r
403          *      @param myname   My name as seen by external systems\r
404          *      @param spooldir The directory where temporary files live\r
405          *      @param port     The port number for URLs\r
406          *      @param nodeauthkey      The keying string used to generate node authentication credentials\r
407          */\r
408         public NodeConfig(ProvData pd, String myname, String spooldir, int port, String nodeauthkey) {\r
409                 this.myname = myname;\r
410                 for (ProvParam p: pd.getParams()) {\r
411                         params.put(p.getName(), p.getValue());\r
412                 }\r
413                 Vector<DestInfo>        div = new Vector<DestInfo>();\r
414                 myauth = NodeUtils.getNodeAuthHdr(myname, nodeauthkey);\r
415                 for (ProvNode pn: pd.getNodes()) {\r
416                         String cn = pn.getCName();\r
417                         if (nodeinfo.get(cn) != null) {\r
418                                 continue;\r
419                         }\r
420                         String auth = NodeUtils.getNodeAuthHdr(cn, nodeauthkey);\r
421                         DestInfo di = new DestInfo("n:" + cn, spooldir + "/n/" + cn, null, "n2n-" + cn, "https://" + cn + ":" + port + "/internal/publish", cn, myauth, false, true);\r
422                         (new File(di.getSpool())).mkdirs();\r
423                         div.add(di);\r
424                         nodeinfo.put(cn, di);\r
425                         nodes.put(auth, new IsFrom(cn));\r
426                 }\r
427                 PathFinder pf = new PathFinder(myname, nodeinfo.keySet().toArray(new String[nodeinfo.size()]), pd.getHops());\r
428                 Hashtable<String, Vector<Redirection>> rdtab = new Hashtable<String, Vector<Redirection>>();\r
429                 for (ProvForceIngress pfi: pd.getForceIngress()) {\r
430                         Vector<Redirection> v = rdtab.get(pfi.getFeedId());\r
431                         if (v == null) {\r
432                                 v = new Vector<Redirection>();\r
433                                 rdtab.put(pfi.getFeedId(), v);\r
434                         }\r
435                         Redirection r = new Redirection();\r
436                         if (pfi.getSubnet() != null) {\r
437                                 r.snm = new SubnetMatcher(pfi.getSubnet());\r
438                         }\r
439                         r.user = pfi.getUser();\r
440                         r.nodes = pfi.getNodes();\r
441                         v.add(r);\r
442                 }\r
443                 Hashtable<String, Hashtable<String, String>> pfutab = new Hashtable<String, Hashtable<String, String>>();\r
444                 for (ProvFeedUser pfu: pd.getFeedUsers()) {\r
445                         Hashtable<String, String> t = pfutab.get(pfu.getFeedId());\r
446                         if (t == null) {\r
447                                 t = new Hashtable<String, String>();\r
448                                 pfutab.put(pfu.getFeedId(), t);\r
449                         }\r
450                         t.put(pfu.getCredentials(), pfu.getUser());\r
451                 }\r
452                 Hashtable<String, String> egrtab = new Hashtable<String, String>();\r
453                 for (ProvForceEgress pfe: pd.getForceEgress()) {\r
454                         if (pfe.getNode().equals(myname) || nodeinfo.get(pfe.getNode()) == null) {\r
455                                 continue;\r
456                         }\r
457                         egrtab.put(pfe.getSubId(), pfe.getNode());\r
458                 }\r
459                 Hashtable<String, Vector<SubnetMatcher>> pfstab = new Hashtable<String, Vector<SubnetMatcher>>();\r
460                 for (ProvFeedSubnet pfs: pd.getFeedSubnets()) {\r
461                         Vector<SubnetMatcher> v = pfstab.get(pfs.getFeedId());\r
462                         if (v == null) {\r
463                                 v = new Vector<SubnetMatcher>();\r
464                                 pfstab.put(pfs.getFeedId(), v);\r
465                         }\r
466                         v.add(new SubnetMatcher(pfs.getCidr()));\r
467                 }\r
468                 Hashtable<String, StringBuffer> ttab = new Hashtable<String, StringBuffer>();\r
469                 HashSet<String> allfeeds = new HashSet<String>();\r
470                 for (ProvFeed pfx: pd.getFeeds()) {\r
471                         if (pfx.getStatus() == null) {\r
472                                 allfeeds.add(pfx.getId());\r
473                         }\r
474                 }\r
475                 for (ProvSubscription ps: pd.getSubscriptions()) {\r
476                         String sid = ps.getSubId();\r
477                         String fid = ps.getFeedId();\r
478                         if (!allfeeds.contains(fid)) {\r
479                                 continue;\r
480                         }\r
481                         if (subinfo.get(sid) != null) {\r
482                                 continue;\r
483                         }\r
484                         int sididx = 999;\r
485                         try {\r
486                                 sididx = Integer.parseInt(sid);\r
487                                 sididx -= sididx % 100;\r
488                         } catch (Exception e) {\r
489                         }\r
490                         String siddir = sididx + "/" + sid;\r
491                         DestInfo di = new DestInfo("s:" + sid, spooldir + "/s/" + siddir, sid, fid, ps.getURL(), ps.getAuthUser(), ps.getCredentials(), ps.isMetaDataOnly(), ps.isUsing100());\r
492                         (new File(di.getSpool())).mkdirs();\r
493                         div.add(di);\r
494                         subinfo.put(sid, di);\r
495                         String egr = egrtab.get(sid);\r
496                         if (egr != null) {\r
497                                 sid = pf.getPath(egr) + sid;\r
498                         }\r
499                         StringBuffer sb = ttab.get(fid);\r
500                         if (sb == null) {\r
501                                 sb = new StringBuffer();\r
502                                 ttab.put(fid, sb);\r
503                         }\r
504                         sb.append(' ').append(sid);\r
505                 }\r
506                 alldests = div.toArray(new DestInfo[div.size()]);\r
507                 for (ProvFeed pfx: pd.getFeeds()) {\r
508                         String fid = pfx.getId();\r
509                         Feed f = feeds.get(fid);\r
510                         if (f != null) {\r
511                                 continue;\r
512                         }\r
513                         f = new Feed();\r
514                         feeds.put(fid, f);\r
515                         f.loginfo = pfx.getLogData();\r
516                         f.status = pfx.getStatus();\r
517                         Vector<SubnetMatcher> v1 = pfstab.get(fid);\r
518                         if (v1 == null) {\r
519                                 f.subnets = new SubnetMatcher[0];\r
520                         } else {\r
521                                 f.subnets = v1.toArray(new SubnetMatcher[v1.size()]);\r
522                         }\r
523                         Hashtable<String, String> h1 = pfutab.get(fid);\r
524                         if (h1 == null) {\r
525                                 h1 = new Hashtable<String, String>();\r
526                         }\r
527                         f.authusers = h1;\r
528                         Vector<Redirection> v2 = rdtab.get(fid);\r
529                         if (v2 == null) {\r
530                                 f.redirections = new Redirection[0];\r
531                         } else {\r
532                                 f.redirections = v2.toArray(new Redirection[v2.size()]);\r
533                         }\r
534                         StringBuffer sb = ttab.get(fid);\r
535                         if (sb == null) {\r
536                                 f.targets = new Target[0];\r
537                         } else {\r
538                                 f.targets = parseRouting(sb.toString());\r
539                         }\r
540                 }\r
541         }\r
542         /**\r
543          *      Parse a target string into an array of targets\r
544          *      @param routing Target string\r
545          *      @return Array of targets.\r
546          */\r
547         public Target[] parseRouting(String routing) {\r
548                 routing = routing.trim();\r
549                 if ("".equals(routing)) {\r
550                         return(new Target[0]);\r
551                 }\r
552                 String[] xx = routing.split("\\s+");\r
553                 Hashtable<String, Target> tmap = new Hashtable<String, Target>();\r
554                 HashSet<String> subset = new HashSet<String>();\r
555                 Vector<Target> tv = new Vector<Target>();\r
556                 Target[] ret = new Target[xx.length];\r
557                 for (int i = 0; i < xx.length; i++) {\r
558                         String t = xx[i];\r
559                         int j = t.indexOf('/');\r
560                         if (j == -1) {\r
561                                 DestInfo di = subinfo.get(t);\r
562                                 if (di == null) {\r
563                                         tv.add(new Target(null, t));\r
564                                 } else {\r
565                                         if (!subset.contains(t)) {\r
566                                                 subset.add(t);\r
567                                                 tv.add(new Target(di, null));\r
568                                         }\r
569                                 }\r
570                         } else {\r
571                                 String node = t.substring(0, j);\r
572                                 String rtg = t.substring(j + 1);\r
573                                 DestInfo di = nodeinfo.get(node);\r
574                                 if (di == null) {\r
575                                         tv.add(new Target(null, t));\r
576                                 } else {\r
577                                         Target tt = tmap.get(node);\r
578                                         if (tt == null) {\r
579                                                 tt = new Target(di, rtg);\r
580                                                 tmap.put(node, tt);\r
581                                                 tv.add(tt);\r
582                                         } else {\r
583                                                 tt.addRouting(rtg);\r
584                                         }\r
585                                 }\r
586                         }\r
587                 }\r
588                 return(tv.toArray(new Target[tv.size()]));\r
589         }\r
590         /**\r
591          *      Check whether this is a valid node-to-node transfer\r
592          *      @param credentials      Credentials offered by the supposed node\r
593          *      @param ip       IP address the request came from\r
594          */\r
595         public boolean isAnotherNode(String credentials, String ip) {\r
596                 IsFrom n = nodes.get(credentials);\r
597                 return (n != null && n.isFrom(ip));\r
598         }\r
599         /**\r
600          *      Check whether publication is allowed.\r
601          *      @param feedid   The ID of the feed being requested.\r
602          *      @param credentials      The offered credentials\r
603          *      @param ip       The requesting IP address\r
604          */\r
605         public String isPublishPermitted(String feedid, String credentials, String ip) {\r
606                 Feed f = feeds.get(feedid);\r
607                 String nf = "Feed does not exist";\r
608                 if (f != null) {\r
609                         nf = f.status;\r
610                 }\r
611                 if (nf != null) {\r
612                         return(nf);\r
613                 }\r
614                 String user = f.authusers.get(credentials);\r
615                 if (user == null) {\r
616                         return("Publisher not permitted for this feed");\r
617                 }\r
618                 if (f.subnets.length == 0) {\r
619                         return(null);\r
620                 }\r
621                 byte[] addr = NodeUtils.getInetAddress(ip);\r
622                 for (SubnetMatcher snm: f.subnets) {\r
623                         if (snm.matches(addr)) {\r
624                                 return(null);\r
625                         }\r
626                 }\r
627                 return("Publisher not permitted for this feed");\r
628         }\r
629         /**\r
630          *      Get authenticated user\r
631          */\r
632         public String getAuthUser(String feedid, String credentials) {\r
633                 return(feeds.get(feedid).authusers.get(credentials));\r
634         }\r
635         /**\r
636          *      Check if the request should be redirected to a different ingress node\r
637          */\r
638         public String getIngressNode(String feedid, String user, String ip) {\r
639                 Feed f = feeds.get(feedid);\r
640                 if (f.redirections.length == 0) {\r
641                         return(null);\r
642                 }\r
643                 byte[] addr = NodeUtils.getInetAddress(ip);\r
644                 for (Redirection r: f.redirections) {\r
645                         if (r.user != null && !user.equals(r.user)) {\r
646                                 continue;\r
647                         }\r
648                         if (r.snm != null && !r.snm.matches(addr)) {\r
649                                 continue;\r
650                         }\r
651                         for (String n: r.nodes) {\r
652                                 if (myname.equals(n)) {\r
653                                         return(null);\r
654                                 }\r
655                         }\r
656                         if (r.nodes.length == 0) {\r
657                                 return(null);\r
658                         }\r
659                         return(r.nodes[rrcntr++ % r.nodes.length]);\r
660                 }\r
661                 return(null);\r
662         }\r
663         /**\r
664          *      Get a provisioned configuration parameter\r
665          */\r
666         public String getProvParam(String name) {\r
667                 return(params.get(name));\r
668         }\r
669         /**\r
670          *      Get all the DestInfos\r
671          */\r
672         public DestInfo[]       getAllDests() {\r
673                 return(alldests);\r
674         }\r
675         /**\r
676          *      Get the targets for a feed\r
677          *      @param feedid   The feed ID\r
678          *      @return The targets this feed should be delivered to\r
679          */\r
680         public Target[] getTargets(String feedid) {\r
681                 if (feedid == null) {\r
682                         return(new Target[0]);\r
683                 }\r
684                 Feed f = feeds.get(feedid);\r
685                 if (f == null) {\r
686                         return(new Target[0]);\r
687                 }\r
688                 return(f.targets);\r
689         }\r
690         /**\r
691          *      Get the feed ID for a subscription\r
692          *      @param subid    The subscription ID\r
693          *      @return The feed ID\r
694          */\r
695         public String getFeedId(String subid) {\r
696                 DestInfo di = subinfo.get(subid);\r
697                 if (di == null) {\r
698                         return(null);\r
699                 }\r
700                 return(di.getLogData());\r
701         }\r
702         /**\r
703          *      Get the spool directory for a subscription\r
704          *      @param subid    The subscription ID\r
705          *      @return The spool directory\r
706          */\r
707         public String getSpoolDir(String subid) {\r
708                 DestInfo di = subinfo.get(subid);\r
709                 if (di == null) {\r
710                         return(null);\r
711                 }\r
712                 return(di.getSpool());\r
713         }\r
714         /**\r
715          *      Get the Authorization value this node uses\r
716          *      @return The Authorization header value for this node\r
717          */\r
718         public String getMyAuth() {\r
719                 return(myauth);\r
720         }\r
721 \r
722 }\r