1 /*******************************************************************************
2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 * ============LICENSE_END=========================================================
19 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
21 *******************************************************************************/
22 package com.att.nsa.mr.client;
24 import java.util.Collection;
25 import java.util.Iterator;
26 import java.util.LinkedList;
27 import java.util.Random;
29 import java.util.TreeSet;
30 import java.util.Vector;
31 import java.util.concurrent.DelayQueue;
32 import java.util.concurrent.Delayed;
33 import java.util.concurrent.TimeUnit;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
37 public class HostSelector
39 private final TreeSet<String> fBaseHosts;
40 private final DelayQueue<BlacklistEntry> fBlacklist;
41 private String fIdealHost;
42 private String fCurrentHost;
43 private static final Logger log = LoggerFactory.getLogger(HostSelector.class);
45 public HostSelector(String hostPart)
47 this(makeSet(hostPart), null);
50 public HostSelector(Collection<String> baseHosts)
52 this(baseHosts, null);
55 public HostSelector(Collection<String> baseHosts, String signature)
57 if (baseHosts.isEmpty())
59 throw new IllegalArgumentException("At least one host must be provided.");
62 this.fBaseHosts = new TreeSet(baseHosts);
63 this.fBlacklist = new DelayQueue();
64 this.fIdealHost = null;
66 if (signature == null) {
70 int value = signature.hashCode();
72 index = Math.abs(value) % baseHosts.size();
74 Iterator it = this.fBaseHosts.iterator();
79 this.fIdealHost = ((String)it.next());
82 public String selectBaseHost()
84 if (this.fCurrentHost == null)
88 return this.fCurrentHost;
91 public void reportReachabilityProblem(long blacklistUnit, TimeUnit blacklistTimeUnit)
93 if (this.fCurrentHost == null)
95 log.warn("Reporting reachability problem, but no host is currently selected.");
98 if (blacklistUnit > 0L)
100 for (BlacklistEntry be : this.fBlacklist)
102 if (be.getHost().equals(this.fCurrentHost))
108 LinkedList devNull = new LinkedList();
109 this.fBlacklist.drainTo(devNull);
111 if (this.fCurrentHost != null)
113 this.fBlacklist.add(new BlacklistEntry(this.fCurrentHost, TimeUnit.MILLISECONDS.convert(blacklistUnit, blacklistTimeUnit)));
116 this.fCurrentHost = null;
119 private String makeSelection()
121 TreeSet workingSet = new TreeSet(this.fBaseHosts);
123 LinkedList devNull = new LinkedList();
124 this.fBlacklist.drainTo(devNull);
125 for (BlacklistEntry be : this.fBlacklist)
127 workingSet.remove(be.getHost());
130 if (workingSet.isEmpty())
132 log.warn("All hosts were blacklisted; reverting to full set of hosts.");
133 workingSet.addAll(this.fBaseHosts);
134 this.fCurrentHost = null;
137 String selection = null;
138 if ((this.fCurrentHost != null) && (workingSet.contains(this.fCurrentHost)))
140 selection = this.fCurrentHost;
142 else if ((this.fIdealHost != null) && (workingSet.contains(this.fIdealHost)))
144 selection = this.fIdealHost;
149 int value = new Random().nextInt();
150 Vector v = new Vector(workingSet);
152 index = Math.abs(value) % workingSet.size();
154 selection = (String)v.elementAt(index);
157 this.fCurrentHost = selection;
158 return this.fCurrentHost;
161 private static Set<String> makeSet(String s)
163 TreeSet set = new TreeSet();
167 private static class BlacklistEntry implements Delayed {
168 private final String fHost;
169 private long fExpireAtMs;
171 public BlacklistEntry(String host, long delayMs) {
173 this.fExpireAtMs = (System.currentTimeMillis() + delayMs);
176 public void expireNow()
178 this.fExpireAtMs = 0L;
181 public String getHost()
186 public int compareTo(Delayed o)
188 Long thisDelay = Long.valueOf(getDelay(TimeUnit.MILLISECONDS));
189 return thisDelay.compareTo(Long.valueOf(o.getDelay(TimeUnit.MILLISECONDS)));
192 public long getDelay(TimeUnit unit)
194 long remainingMs = this.fExpireAtMs - System.currentTimeMillis();
195 return unit.convert(remainingMs, TimeUnit.MILLISECONDS);