-/*******************************************************************************\r
- * ============LICENSE_START==================================================\r
- * * org.onap.dmaap\r
- * * ===========================================================================\r
- * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
- * * ===========================================================================\r
- * * Licensed under the Apache License, Version 2.0 (the "License");\r
- * * you may not use this file except in compliance with the License.\r
- * * You may obtain a copy of the License at\r
- * * \r
- * * http://www.apache.org/licenses/LICENSE-2.0\r
- * * \r
- * * Unless required by applicable law or agreed to in writing, software\r
- * * distributed under the License is distributed on an "AS IS" BASIS,\r
- * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * * See the License for the specific language governing permissions and\r
- * * limitations under the License.\r
- * * ============LICENSE_END====================================================\r
- * *\r
- * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
- * *\r
- ******************************************************************************/\r
-\r
-\r
-package org.onap.dmaap.datarouter.node;\r
-\r
-import java.util.*;\r
-import java.io.*;\r
-\r
-/**\r
- * Processed configuration for this node.\r
- * <p>\r
- * The NodeConfig represents a processed configuration from the Data Router\r
- * provisioning server. Each time configuration data is received from the\r
- * provisioning server, a new NodeConfig is created and the previous one\r
- * discarded.\r
- */\r
-public class NodeConfig {\r
- /**\r
- * Raw configuration entry for a data router node\r
- */\r
- public static class ProvNode {\r
- private String cname;\r
- /**\r
- * Construct a node configuration entry.\r
- * @param cname The cname of the node.\r
- */\r
- public ProvNode(String cname) {\r
- this.cname = cname;\r
- }\r
- /**\r
- * Get the cname of the node\r
- */\r
- public String getCName() {\r
- return(cname);\r
- }\r
- }\r
- /**\r
- * Raw configuration entry for a provisioning parameter\r
- */\r
- public static class ProvParam {\r
- private String name;\r
- private String value;\r
- /**\r
- * Construct a provisioning parameter configuration entry.\r
- * @param name The name of the parameter.\r
- * @param value The value of the parameter.\r
- */\r
- public ProvParam(String name, String value) {\r
- this.name = name;\r
- this.value = value;\r
- }\r
- /**\r
- * Get the name of the parameter.\r
- */\r
- public String getName() {\r
- return(name);\r
- }\r
- /**\r
- * Get the value of the parameter.\r
- */\r
- public String getValue() {\r
- return(value);\r
- }\r
- }\r
- /**\r
- * Raw configuration entry for a data feed.\r
- */\r
- public static class ProvFeed {\r
- private String id;\r
- private String logdata;\r
- private String status;\r
- /**\r
- * Construct a feed configuration entry.\r
- * @param id The feed ID of the entry.\r
- * @param logdata String for log entries about the entry.\r
- * @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
- */\r
- public ProvFeed(String id, String logdata, String status) {\r
- this.id = id;\r
- this.logdata = logdata;\r
- this.status = status;\r
- }\r
- /**\r
- * Get the feed id of the data feed.\r
- */\r
- public String getId() {\r
- return(id);\r
- }\r
- /**\r
- * Get the log data of the data feed.\r
- */\r
- public String getLogData() {\r
- return(logdata);\r
- }\r
- /**\r
- * Get the status of the data feed.\r
- */\r
- public String getStatus() {\r
- return(status);\r
- }\r
- }\r
- /**\r
- * Raw configuration entry for a feed user.\r
- */\r
- public static class ProvFeedUser {\r
- private String feedid;\r
- private String user;\r
- private String credentials;\r
- /**\r
- * Construct a feed user configuration entry\r
- * @param feedid The feed id.\r
- * @param user The user that will publish to the feed.\r
- * @param credentials The Authorization header the user will use to publish.\r
- */\r
- public ProvFeedUser(String feedid, String user, String credentials) {\r
- this.feedid = feedid;\r
- this.user = user;\r
- this.credentials = credentials;\r
- }\r
- /**\r
- * Get the feed id of the feed user.\r
- */\r
- public String getFeedId() {\r
- return(feedid);\r
- }\r
- /**\r
- * Get the user for the feed user.\r
- */\r
- public String getUser() {\r
- return(user);\r
- }\r
- /**\r
- * Get the credentials for the feed user.\r
- */\r
- public String getCredentials() {\r
- return(credentials);\r
- }\r
- }\r
- /**\r
- * Raw configuration entry for a feed subnet\r
- */\r
- public static class ProvFeedSubnet {\r
- private String feedid;\r
- private String cidr;\r
- /**\r
- * Construct a feed subnet configuration entry\r
- * @param feedid The feed ID\r
- * @param cidr The CIDR allowed to publish to the feed.\r
- */\r
- public ProvFeedSubnet(String feedid, String cidr) {\r
- this.feedid = feedid;\r
- this.cidr = cidr;\r
- }\r
- /**\r
- * Get the feed id of the feed subnet.\r
- */\r
- public String getFeedId() {\r
- return(feedid);\r
- }\r
- /**\r
- * Get the CIDR of the feed subnet.\r
- */\r
- public String getCidr() {\r
- return(cidr);\r
- }\r
- }\r
- /**\r
- * Raw configuration entry for a subscription\r
- */\r
- public static class ProvSubscription {\r
- private String subid;\r
- private String feedid;\r
- private String url;\r
- private String authuser;\r
- private String credentials;\r
- private boolean metaonly;\r
- private boolean use100;\r
- /**\r
- * Construct a subscription configuration entry\r
- * @param subid The subscription ID\r
- * @param feedid The feed ID\r
- * @param url The base delivery URL (not including the fileid)\r
- * @param authuser The user in the credentials used to deliver\r
- * @param credentials The credentials used to authenticate to the delivery URL exactly as they go in the Authorization header.\r
- * @param metaonly Is this a meta data only subscription?\r
- * @param use100 Should we send Expect: 100-continue?\r
- */\r
- public ProvSubscription(String subid, String feedid, String url, String authuser, String credentials, boolean metaonly, boolean use100) {\r
- this.subid = subid;\r
- this.feedid = feedid;\r
- this.url = url;\r
- this.authuser = authuser;\r
- this.credentials = credentials;\r
- this.metaonly = metaonly;\r
- this.use100 = use100;\r
- }\r
- /**\r
- * Get the subscription ID\r
- */\r
- public String getSubId() {\r
- return(subid);\r
- }\r
- /**\r
- * Get the feed ID\r
- */\r
- public String getFeedId() {\r
- return(feedid);\r
- }\r
- /**\r
- * Get the delivery URL\r
- */\r
- public String getURL() {\r
- return(url);\r
- }\r
- /**\r
- * Get the user\r
- */\r
- public String getAuthUser() {\r
- return(authuser);\r
- }\r
- /**\r
- * Get the delivery credentials\r
- */\r
- public String getCredentials() {\r
- return(credentials);\r
- }\r
- /**\r
- * Is this a meta data only subscription?\r
- */\r
- public boolean isMetaDataOnly() {\r
- return(metaonly);\r
- }\r
- /**\r
- * Should we send Expect: 100-continue?\r
- */\r
- public boolean isUsing100() {\r
- return(use100);\r
- }\r
- }\r
- /**\r
- * Raw configuration entry for controlled ingress to the data router node\r
- */\r
- public static class ProvForceIngress {\r
- private String feedid;\r
- private String subnet;\r
- private String user;\r
- private String[] nodes;\r
- /**\r
- * Construct a forced ingress configuration entry\r
- * @param feedid The feed ID that this entry applies to\r
- * @param subnet The CIDR for which publisher IP addresses this entry applies to or "" if it applies to all publisher IP addresses\r
- * @param user The publishing user this entry applies to or "" if it applies to all publishing users.\r
- * @param nodes The array of FQDNs of the data router nodes to redirect publication attempts to.\r
- */\r
- public ProvForceIngress(String feedid, String subnet, String user, String[] nodes) {\r
- this.feedid = feedid;\r
- this.subnet = subnet;\r
- this.user = user;\r
- this.nodes = nodes;\r
- }\r
- /**\r
- * Get the feed ID\r
- */\r
- public String getFeedId() {\r
- return(feedid);\r
- }\r
- /**\r
- * Get the subnet\r
- */\r
- public String getSubnet() {\r
- return(subnet);\r
- }\r
- /**\r
- * Get the user\r
- */\r
- public String getUser() {\r
- return(user);\r
- }\r
- /**\r
- * Get the node\r
- */\r
- public String[] getNodes() {\r
- return(nodes);\r
- }\r
- }\r
- /**\r
- * Raw configuration entry for controlled egress from the data router\r
- */\r
- public static class ProvForceEgress {\r
- private String subid;\r
- private String node;\r
- /**\r
- * Construct a forced egress configuration entry\r
- * @param subid The subscription ID the subscription with forced egress\r
- * @param node The node handling deliveries for this subscription\r
- */\r
- public ProvForceEgress(String subid, String node) {\r
- this.subid = subid;\r
- this.node = node;\r
- }\r
- /**\r
- * Get the subscription ID\r
- */\r
- public String getSubId() {\r
- return(subid);\r
- }\r
- /**\r
- * Get the node\r
- */\r
- public String getNode() {\r
- return(node);\r
- }\r
- }\r
- /**\r
- * Raw configuration entry for routing within the data router network\r
- */\r
- public static class ProvHop {\r
- private String from;\r
- private String to;\r
- private String via;\r
- /**\r
- * A human readable description of this entry\r
- */\r
- public String toString() {\r
- return("Hop " + from + "->" + to + " via " + via);\r
- }\r
- /**\r
- * Construct a hop entry\r
- * @param from The FQDN of the node with the data to be delivered\r
- * @param to The FQDN of the node that will deliver to the subscriber\r
- * @param via The FQDN of the node where the from node should send the data\r
- */\r
- public ProvHop(String from, String to, String via) {\r
- this.from = from;\r
- this.to = to;\r
- this.via = via;\r
- }\r
- /**\r
- * Get the from node\r
- */\r
- public String getFrom() {\r
- return(from);\r
- }\r
- /**\r
- * Get the to node\r
- */\r
- public String getTo() {\r
- return(to);\r
- }\r
- /**\r
- * Get the next intermediate node\r
- */\r
- public String getVia() {\r
- return(via);\r
- }\r
- }\r
- private static class Redirection {\r
- public SubnetMatcher snm;\r
- public String user;\r
- public String[] nodes;\r
- }\r
- private static class Feed {\r
- public String loginfo;\r
- public String status;\r
- public SubnetMatcher[] subnets;\r
- public Hashtable<String, String> authusers = new Hashtable<String, String>();\r
- public Redirection[] redirections;\r
- public Target[] targets;\r
- }\r
- private Hashtable<String, String> params = new Hashtable<String, String>();\r
- private Hashtable<String, Feed> feeds = new Hashtable<String, Feed>();\r
- private Hashtable<String, DestInfo> nodeinfo = new Hashtable<String, DestInfo>();\r
- private Hashtable<String, DestInfo> subinfo = new Hashtable<String, DestInfo>();\r
- private Hashtable<String, IsFrom> nodes = new Hashtable<String, IsFrom>();\r
- private String myname;\r
- private String myauth;\r
- private DestInfo[] alldests;\r
- private int rrcntr;\r
- /**\r
- * Process the raw provisioning data to configure this node\r
- * @param pd The parsed provisioning data\r
- * @param myname My name as seen by external systems\r
- * @param spooldir The directory where temporary files live\r
- * @param port The port number for URLs\r
- * @param nodeauthkey The keying string used to generate node authentication credentials\r
- */\r
- public NodeConfig(ProvData pd, String myname, String spooldir, int port, String nodeauthkey) {\r
- this.myname = myname;\r
- for (ProvParam p: pd.getParams()) {\r
- params.put(p.getName(), p.getValue());\r
- }\r
- Vector<DestInfo> div = new Vector<DestInfo>();\r
- myauth = NodeUtils.getNodeAuthHdr(myname, nodeauthkey);\r
- for (ProvNode pn: pd.getNodes()) {\r
- String cn = pn.getCName();\r
- if (nodeinfo.get(cn) != null) {\r
- continue;\r
- }\r
- String auth = NodeUtils.getNodeAuthHdr(cn, nodeauthkey);\r
- DestInfo di = new DestInfo("n:" + cn, spooldir + "/n/" + cn, null, "n2n-" + cn, "https://" + cn + ":" + port + "/internal/publish", cn, myauth, false, true);\r
- (new File(di.getSpool())).mkdirs();\r
- div.add(di);\r
- nodeinfo.put(cn, di);\r
- nodes.put(auth, new IsFrom(cn));\r
- }\r
- PathFinder pf = new PathFinder(myname, nodeinfo.keySet().toArray(new String[nodeinfo.size()]), pd.getHops());\r
- Hashtable<String, Vector<Redirection>> rdtab = new Hashtable<String, Vector<Redirection>>();\r
- for (ProvForceIngress pfi: pd.getForceIngress()) {\r
- Vector<Redirection> v = rdtab.get(pfi.getFeedId());\r
- if (v == null) {\r
- v = new Vector<Redirection>();\r
- rdtab.put(pfi.getFeedId(), v);\r
- }\r
- Redirection r = new Redirection();\r
- if (pfi.getSubnet() != null) {\r
- r.snm = new SubnetMatcher(pfi.getSubnet());\r
- }\r
- r.user = pfi.getUser();\r
- r.nodes = pfi.getNodes();\r
- v.add(r);\r
- }\r
- Hashtable<String, Hashtable<String, String>> pfutab = new Hashtable<String, Hashtable<String, String>>();\r
- for (ProvFeedUser pfu: pd.getFeedUsers()) {\r
- Hashtable<String, String> t = pfutab.get(pfu.getFeedId());\r
- if (t == null) {\r
- t = new Hashtable<String, String>();\r
- pfutab.put(pfu.getFeedId(), t);\r
- }\r
- t.put(pfu.getCredentials(), pfu.getUser());\r
- }\r
- Hashtable<String, String> egrtab = new Hashtable<String, String>();\r
- for (ProvForceEgress pfe: pd.getForceEgress()) {\r
- if (pfe.getNode().equals(myname) || nodeinfo.get(pfe.getNode()) == null) {\r
- continue;\r
- }\r
- egrtab.put(pfe.getSubId(), pfe.getNode());\r
- }\r
- Hashtable<String, Vector<SubnetMatcher>> pfstab = new Hashtable<String, Vector<SubnetMatcher>>();\r
- for (ProvFeedSubnet pfs: pd.getFeedSubnets()) {\r
- Vector<SubnetMatcher> v = pfstab.get(pfs.getFeedId());\r
- if (v == null) {\r
- v = new Vector<SubnetMatcher>();\r
- pfstab.put(pfs.getFeedId(), v);\r
- }\r
- v.add(new SubnetMatcher(pfs.getCidr()));\r
- }\r
- Hashtable<String, StringBuffer> ttab = new Hashtable<String, StringBuffer>();\r
- HashSet<String> allfeeds = new HashSet<String>();\r
- for (ProvFeed pfx: pd.getFeeds()) {\r
- if (pfx.getStatus() == null) {\r
- allfeeds.add(pfx.getId());\r
- }\r
- }\r
- for (ProvSubscription ps: pd.getSubscriptions()) {\r
- String sid = ps.getSubId();\r
- String fid = ps.getFeedId();\r
- if (!allfeeds.contains(fid)) {\r
- continue;\r
- }\r
- if (subinfo.get(sid) != null) {\r
- continue;\r
- }\r
- int sididx = 999;\r
- try {\r
- sididx = Integer.parseInt(sid);\r
- sididx -= sididx % 100;\r
- } catch (Exception e) {\r
- }\r
- String siddir = sididx + "/" + sid;\r
- DestInfo di = new DestInfo("s:" + sid, spooldir + "/s/" + siddir, sid, fid, ps.getURL(), ps.getAuthUser(), ps.getCredentials(), ps.isMetaDataOnly(), ps.isUsing100());\r
- (new File(di.getSpool())).mkdirs();\r
- div.add(di);\r
- subinfo.put(sid, di);\r
- String egr = egrtab.get(sid);\r
- if (egr != null) {\r
- sid = pf.getPath(egr) + sid;\r
- }\r
- StringBuffer sb = ttab.get(fid);\r
- if (sb == null) {\r
- sb = new StringBuffer();\r
- ttab.put(fid, sb);\r
- }\r
- sb.append(' ').append(sid);\r
- }\r
- alldests = div.toArray(new DestInfo[div.size()]);\r
- for (ProvFeed pfx: pd.getFeeds()) {\r
- String fid = pfx.getId();\r
- Feed f = feeds.get(fid);\r
- if (f != null) {\r
- continue;\r
- }\r
- f = new Feed();\r
- feeds.put(fid, f);\r
- f.loginfo = pfx.getLogData();\r
- f.status = pfx.getStatus();\r
- Vector<SubnetMatcher> v1 = pfstab.get(fid);\r
- if (v1 == null) {\r
- f.subnets = new SubnetMatcher[0];\r
- } else {\r
- f.subnets = v1.toArray(new SubnetMatcher[v1.size()]);\r
- }\r
- Hashtable<String, String> h1 = pfutab.get(fid);\r
- if (h1 == null) {\r
- h1 = new Hashtable<String, String>();\r
- }\r
- f.authusers = h1;\r
- Vector<Redirection> v2 = rdtab.get(fid);\r
- if (v2 == null) {\r
- f.redirections = new Redirection[0];\r
- } else {\r
- f.redirections = v2.toArray(new Redirection[v2.size()]);\r
- }\r
- StringBuffer sb = ttab.get(fid);\r
- if (sb == null) {\r
- f.targets = new Target[0];\r
- } else {\r
- f.targets = parseRouting(sb.toString());\r
- }\r
- }\r
- }\r
- /**\r
- * Parse a target string into an array of targets\r
- * @param routing Target string\r
- * @return Array of targets.\r
- */\r
- public Target[] parseRouting(String routing) {\r
- routing = routing.trim();\r
- if ("".equals(routing)) {\r
- return(new Target[0]);\r
- }\r
- String[] xx = routing.split("\\s+");\r
- Hashtable<String, Target> tmap = new Hashtable<String, Target>();\r
- HashSet<String> subset = new HashSet<String>();\r
- Vector<Target> tv = new Vector<Target>();\r
- Target[] ret = new Target[xx.length];\r
- for (int i = 0; i < xx.length; i++) {\r
- String t = xx[i];\r
- int j = t.indexOf('/');\r
- if (j == -1) {\r
- DestInfo di = subinfo.get(t);\r
- if (di == null) {\r
- tv.add(new Target(null, t));\r
- } else {\r
- if (!subset.contains(t)) {\r
- subset.add(t);\r
- tv.add(new Target(di, null));\r
- }\r
- }\r
- } else {\r
- String node = t.substring(0, j);\r
- String rtg = t.substring(j + 1);\r
- DestInfo di = nodeinfo.get(node);\r
- if (di == null) {\r
- tv.add(new Target(null, t));\r
- } else {\r
- Target tt = tmap.get(node);\r
- if (tt == null) {\r
- tt = new Target(di, rtg);\r
- tmap.put(node, tt);\r
- tv.add(tt);\r
- } else {\r
- tt.addRouting(rtg);\r
- }\r
- }\r
- }\r
- }\r
- return(tv.toArray(new Target[tv.size()]));\r
- }\r
- /**\r
- * Check whether this is a valid node-to-node transfer\r
- * @param credentials Credentials offered by the supposed node\r
- * @param ip IP address the request came from\r
- */\r
- public boolean isAnotherNode(String credentials, String ip) {\r
- IsFrom n = nodes.get(credentials);\r
- return (n != null && n.isFrom(ip));\r
- }\r
- /**\r
- * Check whether publication is allowed.\r
- * @param feedid The ID of the feed being requested.\r
- * @param credentials The offered credentials\r
- * @param ip The requesting IP address\r
- */\r
- public String isPublishPermitted(String feedid, String credentials, String ip) {\r
- Feed f = feeds.get(feedid);\r
- String nf = "Feed does not exist";\r
- if (f != null) {\r
- nf = f.status;\r
- }\r
- if (nf != null) {\r
- return(nf);\r
- }\r
- String user = f.authusers.get(credentials);\r
- if (user == null) {\r
- return("Publisher not permitted for this feed");\r
- }\r
- if (f.subnets.length == 0) {\r
- return(null);\r
- }\r
- byte[] addr = NodeUtils.getInetAddress(ip);\r
- for (SubnetMatcher snm: f.subnets) {\r
- if (snm.matches(addr)) {\r
- return(null);\r
- }\r
- }\r
- return("Publisher not permitted for this feed");\r
- }\r
- /**\r
- * Get authenticated user\r
- */\r
- public String getAuthUser(String feedid, String credentials) {\r
- return(feeds.get(feedid).authusers.get(credentials));\r
- }\r
- /**\r
- * Check if the request should be redirected to a different ingress node\r
- */\r
- public String getIngressNode(String feedid, String user, String ip) {\r
- Feed f = feeds.get(feedid);\r
- if (f.redirections.length == 0) {\r
- return(null);\r
- }\r
- byte[] addr = NodeUtils.getInetAddress(ip);\r
- for (Redirection r: f.redirections) {\r
- if (r.user != null && !user.equals(r.user)) {\r
- continue;\r
- }\r
- if (r.snm != null && !r.snm.matches(addr)) {\r
- continue;\r
- }\r
- for (String n: r.nodes) {\r
- if (myname.equals(n)) {\r
- return(null);\r
- }\r
- }\r
- if (r.nodes.length == 0) {\r
- return(null);\r
- }\r
- return(r.nodes[rrcntr++ % r.nodes.length]);\r
- }\r
- return(null);\r
- }\r
- /**\r
- * Get a provisioned configuration parameter\r
- */\r
- public String getProvParam(String name) {\r
- return(params.get(name));\r
- }\r
- /**\r
- * Get all the DestInfos\r
- */\r
- public DestInfo[] getAllDests() {\r
- return(alldests);\r
- }\r
- /**\r
- * Get the targets for a feed\r
- * @param feedid The feed ID\r
- * @return The targets this feed should be delivered to\r
- */\r
- public Target[] getTargets(String feedid) {\r
- if (feedid == null) {\r
- return(new Target[0]);\r
- }\r
- Feed f = feeds.get(feedid);\r
- if (f == null) {\r
- return(new Target[0]);\r
- }\r
- return(f.targets);\r
- }\r
- /**\r
- * Get the feed ID for a subscription\r
- * @param subid The subscription ID\r
- * @return The feed ID\r
- */\r
- public String getFeedId(String subid) {\r
- DestInfo di = subinfo.get(subid);\r
- if (di == null) {\r
- return(null);\r
- }\r
- return(di.getLogData());\r
- }\r
- /**\r
- * Get the spool directory for a subscription\r
- * @param subid The subscription ID\r
- * @return The spool directory\r
- */\r
- public String getSpoolDir(String subid) {\r
- DestInfo di = subinfo.get(subid);\r
- if (di == null) {\r
- return(null);\r
- }\r
- return(di.getSpool());\r
- }\r
- /**\r
- * Get the Authorization value this node uses\r
- * @return The Authorization header value for this node\r
- */\r
- public String getMyAuth() {\r
- return(myauth);\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * ============LICENSE_START==================================================
+ * * org.onap.dmaap
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * ===========================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+
+
+package org.onap.dmaap.datarouter.node;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * Processed configuration for this node.
+ * <p>
+ * The NodeConfig represents a processed configuration from the Data Router provisioning server. Each time
+ * configuration data is received from the provisioning server, a new NodeConfig is created and the previous one
+ * discarded.
+ */
+public class NodeConfig {
+
+ /**
+ * Raw configuration entry for a data router node
+ */
+ public static class ProvNode {
+
+ private String cname;
+
+ /**
+ * Construct a node configuration entry.
+ *
+ * @param cname The cname of the node.
+ */
+ public ProvNode(String cname) {
+ this.cname = cname;
+ }
+
+ /**
+ * Get the cname of the node
+ */
+ public String getCName() {
+ return (cname);
+ }
+ }
+
+ /**
+ * Raw configuration entry for a provisioning parameter
+ */
+ public static class ProvParam {
+
+ private String name;
+ private String value;
+
+ /**
+ * Construct a provisioning parameter configuration entry.
+ *
+ * @param name The name of the parameter.
+ * @param value The value of the parameter.
+ */
+ public ProvParam(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ /**
+ * Get the name of the parameter.
+ */
+ public String getName() {
+ return (name);
+ }
+
+ /**
+ * Get the value of the parameter.
+ */
+ public String getValue() {
+ return (value);
+ }
+ }
+
+ /**
+ * Raw configuration entry for a data feed.
+ */
+ public static class ProvFeed {
+
+ private String id;
+ private String logdata;
+ private String status;
+
+ /**
+ * Construct a feed configuration entry.
+ *
+ * @param id The feed ID of the entry.
+ * @param logdata String for log entries about the entry.
+ * @param status The reason why this feed cannot be used (Feed has been deleted, Feed has been suspended) or
+ * null if it is valid.
+ */
+ public ProvFeed(String id, String logdata, String status) {
+ this.id = id;
+ this.logdata = logdata;
+ this.status = status;
+ }
+
+ /**
+ * Get the feed id of the data feed.
+ */
+ public String getId() {
+ return (id);
+ }
+
+ /**
+ * Get the log data of the data feed.
+ */
+ public String getLogData() {
+ return (logdata);
+ }
+
+ /**
+ * Get the status of the data feed.
+ */
+ public String getStatus() {
+ return (status);
+ }
+ }
+
+ /**
+ * Raw configuration entry for a feed user.
+ */
+ public static class ProvFeedUser {
+
+ private String feedid;
+ private String user;
+ private String credentials;
+
+ /**
+ * Construct a feed user configuration entry
+ *
+ * @param feedid The feed id.
+ * @param user The user that will publish to the feed.
+ * @param credentials The Authorization header the user will use to publish.
+ */
+ public ProvFeedUser(String feedid, String user, String credentials) {
+ this.feedid = feedid;
+ this.user = user;
+ this.credentials = credentials;
+ }
+
+ /**
+ * Get the feed id of the feed user.
+ */
+ public String getFeedId() {
+ return (feedid);
+ }
+
+ /**
+ * Get the user for the feed user.
+ */
+ public String getUser() {
+ return (user);
+ }
+
+ /**
+ * Get the credentials for the feed user.
+ */
+ public String getCredentials() {
+ return (credentials);
+ }
+ }
+
+ /**
+ * Raw configuration entry for a feed subnet
+ */
+ public static class ProvFeedSubnet {
+
+ private String feedid;
+ private String cidr;
+
+ /**
+ * Construct a feed subnet configuration entry
+ *
+ * @param feedid The feed ID
+ * @param cidr The CIDR allowed to publish to the feed.
+ */
+ public ProvFeedSubnet(String feedid, String cidr) {
+ this.feedid = feedid;
+ this.cidr = cidr;
+ }
+
+ /**
+ * Get the feed id of the feed subnet.
+ */
+ public String getFeedId() {
+ return (feedid);
+ }
+
+ /**
+ * Get the CIDR of the feed subnet.
+ */
+ public String getCidr() {
+ return (cidr);
+ }
+ }
+
+ /**
+ * Raw configuration entry for a subscription
+ */
+ public static class ProvSubscription {
+
+ private String subid;
+ private String feedid;
+ private String url;
+ private String authuser;
+ private String credentials;
+ private boolean metaonly;
+ private boolean use100;
+
+ /**
+ * Construct a subscription configuration entry
+ *
+ * @param subid The subscription ID
+ * @param feedid The feed ID
+ * @param url The base delivery URL (not including the fileid)
+ * @param authuser The user in the credentials used to deliver
+ * @param credentials The credentials used to authenticate to the delivery URL exactly as they go in the
+ * Authorization header.
+ * @param metaonly Is this a meta data only subscription?
+ * @param use100 Should we send Expect: 100-continue?
+ */
+ public ProvSubscription(String subid, String feedid, String url, String authuser, String credentials,
+ boolean metaonly, boolean use100) {
+ this.subid = subid;
+ this.feedid = feedid;
+ this.url = url;
+ this.authuser = authuser;
+ this.credentials = credentials;
+ this.metaonly = metaonly;
+ this.use100 = use100;
+ }
+
+ /**
+ * Get the subscription ID
+ */
+ public String getSubId() {
+ return (subid);
+ }
+
+ /**
+ * Get the feed ID
+ */
+ public String getFeedId() {
+ return (feedid);
+ }
+
+ /**
+ * Get the delivery URL
+ */
+ public String getURL() {
+ return (url);
+ }
+
+ /**
+ * Get the user
+ */
+ public String getAuthUser() {
+ return (authuser);
+ }
+
+ /**
+ * Get the delivery credentials
+ */
+ public String getCredentials() {
+ return (credentials);
+ }
+
+ /**
+ * Is this a meta data only subscription?
+ */
+ public boolean isMetaDataOnly() {
+ return (metaonly);
+ }
+
+ /**
+ * Should we send Expect: 100-continue?
+ */
+ public boolean isUsing100() {
+ return (use100);
+ }
+ }
+
+ /**
+ * Raw configuration entry for controlled ingress to the data router node
+ */
+ public static class ProvForceIngress {
+
+ private String feedid;
+ private String subnet;
+ private String user;
+ private String[] nodes;
+
+ /**
+ * Construct a forced ingress configuration entry
+ *
+ * @param feedid The feed ID that this entry applies to
+ * @param subnet The CIDR for which publisher IP addresses this entry applies to or "" if it applies to all
+ * publisher IP addresses
+ * @param user The publishing user this entry applies to or "" if it applies to all publishing users.
+ * @param nodes The array of FQDNs of the data router nodes to redirect publication attempts to.
+ */
+ public ProvForceIngress(String feedid, String subnet, String user, String[] nodes) {
+ this.feedid = feedid;
+ this.subnet = subnet;
+ this.user = user;
+ this.nodes = nodes;
+ }
+
+ /**
+ * Get the feed ID
+ */
+ public String getFeedId() {
+ return (feedid);
+ }
+
+ /**
+ * Get the subnet
+ */
+ public String getSubnet() {
+ return (subnet);
+ }
+
+ /**
+ * Get the user
+ */
+ public String getUser() {
+ return (user);
+ }
+
+ /**
+ * Get the node
+ */
+ public String[] getNodes() {
+ return (nodes);
+ }
+ }
+
+ /**
+ * Raw configuration entry for controlled egress from the data router
+ */
+ public static class ProvForceEgress {
+
+ private String subid;
+ private String node;
+
+ /**
+ * Construct a forced egress configuration entry
+ *
+ * @param subid The subscription ID the subscription with forced egress
+ * @param node The node handling deliveries for this subscription
+ */
+ public ProvForceEgress(String subid, String node) {
+ this.subid = subid;
+ this.node = node;
+ }
+
+ /**
+ * Get the subscription ID
+ */
+ public String getSubId() {
+ return (subid);
+ }
+
+ /**
+ * Get the node
+ */
+ public String getNode() {
+ return (node);
+ }
+ }
+
+ /**
+ * Raw configuration entry for routing within the data router network
+ */
+ public static class ProvHop {
+
+ private String from;
+ private String to;
+ private String via;
+
+ /**
+ * A human readable description of this entry
+ */
+ public String toString() {
+ return ("Hop " + from + "->" + to + " via " + via);
+ }
+
+ /**
+ * Construct a hop entry
+ *
+ * @param from The FQDN of the node with the data to be delivered
+ * @param to The FQDN of the node that will deliver to the subscriber
+ * @param via The FQDN of the node where the from node should send the data
+ */
+ public ProvHop(String from, String to, String via) {
+ this.from = from;
+ this.to = to;
+ this.via = via;
+ }
+
+ /**
+ * Get the from node
+ */
+ public String getFrom() {
+ return (from);
+ }
+
+ /**
+ * Get the to node
+ */
+ public String getTo() {
+ return (to);
+ }
+
+ /**
+ * Get the next intermediate node
+ */
+ public String getVia() {
+ return (via);
+ }
+ }
+
+ private static class Redirection {
+
+ SubnetMatcher snm;
+ String user;
+ String[] nodes;
+ }
+
+ private static class Feed {
+
+ String loginfo;
+ String status;
+ SubnetMatcher[] subnets;
+ Hashtable<String, String> authusers = new Hashtable<String, String>();
+ Redirection[] redirections;
+ Target[] targets;
+ }
+
+ private Hashtable<String, String> params = new Hashtable<String, String>();
+ private Hashtable<String, Feed> feeds = new Hashtable<String, Feed>();
+ private Hashtable<String, DestInfo> nodeinfo = new Hashtable<String, DestInfo>();
+ private Hashtable<String, DestInfo> subinfo = new Hashtable<String, DestInfo>();
+ private Hashtable<String, IsFrom> nodes = new Hashtable<String, IsFrom>();
+ private String myname;
+ private String myauth;
+ private DestInfo[] alldests;
+ private int rrcntr;
+
+ /**
+ * Process the raw provisioning data to configure this node
+ *
+ * @param pd The parsed provisioning data
+ * @param myname My name as seen by external systems
+ * @param spooldir The directory where temporary files live
+ * @param port The port number for URLs
+ * @param nodeauthkey The keying string used to generate node authentication credentials
+ */
+ public NodeConfig(ProvData pd, String myname, String spooldir, int port, String nodeauthkey) {
+ this.myname = myname;
+ for (ProvParam p : pd.getParams()) {
+ params.put(p.getName(), p.getValue());
+ }
+ Vector<DestInfo> div = new Vector<DestInfo>();
+ myauth = NodeUtils.getNodeAuthHdr(myname, nodeauthkey);
+ for (ProvNode pn : pd.getNodes()) {
+ String cn = pn.getCName();
+ if (nodeinfo.get(cn) != null) {
+ continue;
+ }
+ String auth = NodeUtils.getNodeAuthHdr(cn, nodeauthkey);
+ DestInfo di = new DestInfo("n:" + cn, spooldir + "/n/" + cn, null, "n2n-" + cn,
+ "https://" + cn + ":" + port + "/internal/publish", cn, myauth, false, true);
+ (new File(di.getSpool())).mkdirs();
+ div.add(di);
+ nodeinfo.put(cn, di);
+ nodes.put(auth, new IsFrom(cn));
+ }
+ PathFinder pf = new PathFinder(myname, nodeinfo.keySet().toArray(new String[nodeinfo.size()]), pd.getHops());
+ Hashtable<String, Vector<Redirection>> rdtab = new Hashtable<String, Vector<Redirection>>();
+ for (ProvForceIngress pfi : pd.getForceIngress()) {
+ Vector<Redirection> v = rdtab.get(pfi.getFeedId());
+ if (v == null) {
+ v = new Vector<Redirection>();
+ rdtab.put(pfi.getFeedId(), v);
+ }
+ Redirection r = new Redirection();
+ if (pfi.getSubnet() != null) {
+ r.snm = new SubnetMatcher(pfi.getSubnet());
+ }
+ r.user = pfi.getUser();
+ r.nodes = pfi.getNodes();
+ v.add(r);
+ }
+ Hashtable<String, Hashtable<String, String>> pfutab = new Hashtable<String, Hashtable<String, String>>();
+ for (ProvFeedUser pfu : pd.getFeedUsers()) {
+ Hashtable<String, String> t = pfutab.get(pfu.getFeedId());
+ if (t == null) {
+ t = new Hashtable<String, String>();
+ pfutab.put(pfu.getFeedId(), t);
+ }
+ t.put(pfu.getCredentials(), pfu.getUser());
+ }
+ Hashtable<String, String> egrtab = new Hashtable<String, String>();
+ for (ProvForceEgress pfe : pd.getForceEgress()) {
+ if (pfe.getNode().equals(myname) || nodeinfo.get(pfe.getNode()) == null) {
+ continue;
+ }
+ egrtab.put(pfe.getSubId(), pfe.getNode());
+ }
+ Hashtable<String, Vector<SubnetMatcher>> pfstab = new Hashtable<String, Vector<SubnetMatcher>>();
+ for (ProvFeedSubnet pfs : pd.getFeedSubnets()) {
+ Vector<SubnetMatcher> v = pfstab.get(pfs.getFeedId());
+ if (v == null) {
+ v = new Vector<SubnetMatcher>();
+ pfstab.put(pfs.getFeedId(), v);
+ }
+ v.add(new SubnetMatcher(pfs.getCidr()));
+ }
+ Hashtable<String, StringBuffer> ttab = new Hashtable<String, StringBuffer>();
+ HashSet<String> allfeeds = new HashSet<String>();
+ for (ProvFeed pfx : pd.getFeeds()) {
+ if (pfx.getStatus() == null) {
+ allfeeds.add(pfx.getId());
+ }
+ }
+ for (ProvSubscription ps : pd.getSubscriptions()) {
+ String sid = ps.getSubId();
+ String fid = ps.getFeedId();
+ if (!allfeeds.contains(fid)) {
+ continue;
+ }
+ if (subinfo.get(sid) != null) {
+ continue;
+ }
+ int sididx = 999;
+ try {
+ sididx = Integer.parseInt(sid);
+ sididx -= sididx % 100;
+ } catch (Exception e) {
+ }
+ String siddir = sididx + "/" + sid;
+ DestInfo di = new DestInfo("s:" + sid, spooldir + "/s/" + siddir, sid, fid, ps.getURL(), ps.getAuthUser(),
+ ps.getCredentials(), ps.isMetaDataOnly(), ps.isUsing100());
+ (new File(di.getSpool())).mkdirs();
+ div.add(di);
+ subinfo.put(sid, di);
+ String egr = egrtab.get(sid);
+ if (egr != null) {
+ sid = pf.getPath(egr) + sid;
+ }
+ StringBuffer sb = ttab.get(fid);
+ if (sb == null) {
+ sb = new StringBuffer();
+ ttab.put(fid, sb);
+ }
+ sb.append(' ').append(sid);
+ }
+ alldests = div.toArray(new DestInfo[div.size()]);
+ for (ProvFeed pfx : pd.getFeeds()) {
+ String fid = pfx.getId();
+ Feed f = feeds.get(fid);
+ if (f != null) {
+ continue;
+ }
+ f = new Feed();
+ feeds.put(fid, f);
+ f.loginfo = pfx.getLogData();
+ f.status = pfx.getStatus();
+ Vector<SubnetMatcher> v1 = pfstab.get(fid);
+ if (v1 == null) {
+ f.subnets = new SubnetMatcher[0];
+ } else {
+ f.subnets = v1.toArray(new SubnetMatcher[v1.size()]);
+ }
+ Hashtable<String, String> h1 = pfutab.get(fid);
+ if (h1 == null) {
+ h1 = new Hashtable<String, String>();
+ }
+ f.authusers = h1;
+ Vector<Redirection> v2 = rdtab.get(fid);
+ if (v2 == null) {
+ f.redirections = new Redirection[0];
+ } else {
+ f.redirections = v2.toArray(new Redirection[v2.size()]);
+ }
+ StringBuffer sb = ttab.get(fid);
+ if (sb == null) {
+ f.targets = new Target[0];
+ } else {
+ f.targets = parseRouting(sb.toString());
+ }
+ }
+ }
+
+ /**
+ * Parse a target string into an array of targets
+ *
+ * @param routing Target string
+ * @return Array of targets.
+ */
+ public Target[] parseRouting(String routing) {
+ routing = routing.trim();
+ if ("".equals(routing)) {
+ return (new Target[0]);
+ }
+ String[] xx = routing.split("\\s+");
+ Hashtable<String, Target> tmap = new Hashtable<String, Target>();
+ HashSet<String> subset = new HashSet<String>();
+ Vector<Target> tv = new Vector<Target>();
+ Target[] ret = new Target[xx.length];
+ for (int i = 0; i < xx.length; i++) {
+ String t = xx[i];
+ int j = t.indexOf('/');
+ if (j == -1) {
+ DestInfo di = subinfo.get(t);
+ if (di == null) {
+ tv.add(new Target(null, t));
+ } else {
+ if (!subset.contains(t)) {
+ subset.add(t);
+ tv.add(new Target(di, null));
+ }
+ }
+ } else {
+ String node = t.substring(0, j);
+ String rtg = t.substring(j + 1);
+ DestInfo di = nodeinfo.get(node);
+ if (di == null) {
+ tv.add(new Target(null, t));
+ } else {
+ Target tt = tmap.get(node);
+ if (tt == null) {
+ tt = new Target(di, rtg);
+ tmap.put(node, tt);
+ tv.add(tt);
+ } else {
+ tt.addRouting(rtg);
+ }
+ }
+ }
+ }
+ return (tv.toArray(new Target[tv.size()]));
+ }
+
+ /**
+ * Check whether this is a valid node-to-node transfer
+ *
+ * @param credentials Credentials offered by the supposed node
+ * @param ip IP address the request came from
+ */
+ public boolean isAnotherNode(String credentials, String ip) {
+ IsFrom n = nodes.get(credentials);
+ return (n != null && n.isFrom(ip));
+ }
+
+ /**
+ * Check whether publication is allowed.
+ *
+ * @param feedid The ID of the feed being requested.
+ * @param credentials The offered credentials
+ * @param ip The requesting IP address
+ */
+ public String isPublishPermitted(String feedid, String credentials, String ip) {
+ Feed f = feeds.get(feedid);
+ String nf = "Feed does not exist";
+ if (f != null) {
+ nf = f.status;
+ }
+ if (nf != null) {
+ return (nf);
+ }
+ String user = f.authusers.get(credentials);
+ if (user == null) {
+ return ("Publisher not permitted for this feed");
+ }
+ if (f.subnets.length == 0) {
+ return (null);
+ }
+ byte[] addr = NodeUtils.getInetAddress(ip);
+ for (SubnetMatcher snm : f.subnets) {
+ if (snm.matches(addr)) {
+ return (null);
+ }
+ }
+ return ("Publisher not permitted for this feed");
+ }
+
+ /**
+ * Get authenticated user
+ */
+ public String getAuthUser(String feedid, String credentials) {
+ return (feeds.get(feedid).authusers.get(credentials));
+ }
+
+ /**
+ * Check if the request should be redirected to a different ingress node
+ */
+ public String getIngressNode(String feedid, String user, String ip) {
+ Feed f = feeds.get(feedid);
+ if (f.redirections.length == 0) {
+ return (null);
+ }
+ byte[] addr = NodeUtils.getInetAddress(ip);
+ for (Redirection r : f.redirections) {
+ if (r.user != null && !user.equals(r.user)) {
+ continue;
+ }
+ if (r.snm != null && !r.snm.matches(addr)) {
+ continue;
+ }
+ for (String n : r.nodes) {
+ if (myname.equals(n)) {
+ return (null);
+ }
+ }
+ if (r.nodes.length == 0) {
+ return (null);
+ }
+ return (r.nodes[rrcntr++ % r.nodes.length]);
+ }
+ return (null);
+ }
+
+ /**
+ * Get a provisioned configuration parameter
+ */
+ public String getProvParam(String name) {
+ return (params.get(name));
+ }
+
+ /**
+ * Get all the DestInfos
+ */
+ public DestInfo[] getAllDests() {
+ return (alldests);
+ }
+
+ /**
+ * Get the targets for a feed
+ *
+ * @param feedid The feed ID
+ * @return The targets this feed should be delivered to
+ */
+ public Target[] getTargets(String feedid) {
+ if (feedid == null) {
+ return (new Target[0]);
+ }
+ Feed f = feeds.get(feedid);
+ if (f == null) {
+ return (new Target[0]);
+ }
+ return (f.targets);
+ }
+
+ /**
+ * Get the feed ID for a subscription
+ *
+ * @param subid The subscription ID
+ * @return The feed ID
+ */
+ public String getFeedId(String subid) {
+ DestInfo di = subinfo.get(subid);
+ if (di == null) {
+ return (null);
+ }
+ return (di.getLogData());
+ }
+
+ /**
+ * Get the spool directory for a subscription
+ *
+ * @param subid The subscription ID
+ * @return The spool directory
+ */
+ public String getSpoolDir(String subid) {
+ DestInfo di = subinfo.get(subid);
+ if (di == null) {
+ return (null);
+ }
+ return (di.getSpool());
+ }
+
+ /**
+ * Get the Authorization value this node uses
+ *
+ * @return The Authorization header value for this node
+ */
+ public String getMyAuth() {
+ return (myauth);
+ }
+
+}