001: /*
002: * <copyright>
003: *
004: * Copyright 2002-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.core.wp.resolver;
028:
029: import java.util.Collections;
030: import java.util.HashMap;
031: import java.util.HashSet;
032: import java.util.Iterator;
033: import java.util.List;
034: import java.util.Map;
035: import java.util.Set;
036: import org.cougaar.core.component.Component;
037: import org.cougaar.core.component.Service;
038: import org.cougaar.core.component.ServiceBroker;
039: import org.cougaar.core.component.ServiceProvider;
040: import org.cougaar.core.mts.MessageAddress;
041: import org.cougaar.core.service.LoggingService;
042: import org.cougaar.core.service.ThreadService;
043: import org.cougaar.core.thread.Schedulable;
044: import org.cougaar.core.wp.MessageTimeoutUtils;
045: import org.cougaar.core.wp.Parameters;
046: import org.cougaar.core.wp.Timestamp;
047: import org.cougaar.core.wp.bootstrap.BootstrapService;
048: import org.cougaar.core.wp.bootstrap.ServersService;
049: import org.cougaar.core.wp.resolver.SelectService.Client;
050: import org.cougaar.util.GenericStateModelAdapter;
051: import org.cougaar.util.RarelyModifiedList;
052:
053: /**
054: * This component advertises the {@link SelectService}, which controls the
055: * {@link ClientTransport}'s server selection and uses the {@link
056: * BootstrapService} to initialize the cache.
057: * <p>
058: * This implementation uses the {@link BootstrapService} to discover
059: * servers and the {@link PingService} to send ping messages to the
060: * found servers, measuring the round-trip-time (RTT). Once we have a
061: * server, we stop the discovery and use the found servers, selecting
062: * between them based upon the RTT. If the best RTT becomes
063: * unacceptably low, we rediscover and re-ping new servers.
064: * <p>
065: * This component is pluggable, so it can be replaced with an
066: * alternate implementation.
067: */
068: public class SelectManager extends GenericStateModelAdapter implements
069: Component {
070: private ServiceBroker sb;
071: private LoggingService logger;
072: private ThreadService threadService;
073:
074: private SelectManagerConfig config;
075:
076: private Schedulable checkPingsThread;
077:
078: private BootstrapService bootstrapService;
079:
080: private SelectSP selectSP;
081:
082: private RarelyModifiedList selectClients = new RarelyModifiedList();
083:
084: private PingService pingService;
085:
086: private final PingService.Client pingClient = new PingService.Client() {
087: public void pingAnswer(MessageAddress addr, long rtt) {
088: SelectManager.this .pingAnswer(addr, rtt);
089: }
090: };
091:
092: private ServersService serversService;
093:
094: private final ServersService.Client serversClient = new ServersService.Client() {
095: public void add(MessageAddress addr) {
096: SelectManager.this .addServer(addr);
097: }
098:
099: public void addAll(Set s) {
100: for (Iterator iter = s.iterator(); iter.hasNext();) {
101: addServer((MessageAddress) iter.next());
102: }
103: }
104:
105: public void remove(MessageAddress addr) {
106: SelectManager.this .removeServer(addr);
107: }
108:
109: public void removeAll(Set s) {
110: for (Iterator iter = s.iterator(); iter.hasNext();) {
111: removeServer((MessageAddress) iter.next());
112: }
113: }
114: };
115:
116: private final Object lock = new Object();
117:
118: private boolean searching;
119: private boolean foundAny;
120: private long pingDeadline;
121:
122: // map from MessageAddress String address to Entry
123: //
124: // Map<String, Entry>
125: private final Map entries = new HashMap();
126:
127: private long selectTime;
128: private long selectTimeout;
129: private MessageAddress selectAddr;
130:
131: // memoize the target, since messages with attributes don't
132: // implement "equals()" or "hashCode()" correctly. By using
133: // a memoized value we allow our client to use a map of
134: // addresses.
135: private MessageAddress memoAddr;
136: private long memoDeadline;
137: private MessageAddress memoTarget;
138:
139: public void setParameter(Object o) {
140: configure(o);
141: }
142:
143: public void setServiceBroker(ServiceBroker sb) {
144: this .sb = sb;
145: }
146:
147: public void setLoggingService(LoggingService logger) {
148: this .logger = logger;
149: }
150:
151: public void setThreadService(ThreadService threadService) {
152: this .threadService = threadService;
153: }
154:
155: private void configure(Object o) {
156: if (config != null) {
157: return;
158: }
159: config = new SelectManagerConfig(o);
160: }
161:
162: public void load() {
163: super .load();
164:
165: if (logger.isDebugEnabled()) {
166: logger.debug("Loading resolver select manager");
167: }
168:
169: configure(null);
170:
171: // monitor ping-based searching
172: Runnable checkPingsRunner = new Runnable() {
173: public void run() {
174: // assert (thread == checkPingsThread);
175: checkPings();
176: }
177: };
178: checkPingsThread = threadService.getThread(this ,
179: checkPingsRunner,
180: "White pages server selector check pings");
181:
182: // listen for the services
183: ServiceFinder.Callback sfc = new ServiceFinder.Callback() {
184: public void foundService(Service s) {
185: SelectManager.this .foundService(s);
186: }
187: };
188: if (logger.isDetailEnabled()) {
189: logger.detail("findLater("
190: + "PingService, BootstrapService, ServersService)");
191: }
192: ServiceFinder.findServiceLater(sb, PingService.class,
193: pingClient, sfc);
194: ServiceFinder.findServiceLater(sb, BootstrapService.class,
195: null, sfc);
196: ServiceFinder.findServiceLater(sb, ServersService.class,
197: serversClient, sfc);
198:
199: // advertise our service
200: selectSP = new SelectSP();
201: sb.addService(SelectService.class, selectSP);
202: }
203:
204: private void foundService(Service s) {
205: synchronized (lock) {
206: if (logger.isDetailEnabled()) {
207: logger.detail("foundService(" + s + "), searching="
208: + searching);
209: }
210: if (s instanceof PingService) {
211: pingService = (PingService) s;
212: if (searching) {
213: sendPings();
214: }
215: } else if (s instanceof BootstrapService) {
216: bootstrapService = (BootstrapService) s;
217: if (searching) {
218: if (logger.isDetailEnabled()) {
219: logger.detail("bs.startSearching");
220: }
221: bootstrapService.startSearching();
222: }
223: } else if (s instanceof ServersService) {
224: serversService = (ServersService) s;
225: }
226: }
227: }
228:
229: public void unload() {
230: if (selectSP != null) {
231: sb.revokeService(SelectService.class, selectSP);
232: selectSP = null;
233: }
234: if (serversService != null) {
235: sb.releaseService(serversClient, ServersService.class,
236: serversService);
237: serversService = null;
238: }
239: if (bootstrapService != null) {
240: sb.releaseService(this , BootstrapService.class,
241: bootstrapService);
242: }
243: if (pingService != null) {
244: sb.releaseService(pingClient, PingService.class,
245: pingService);
246: }
247: if (logger != null) {
248: sb.releaseService(this , LoggingService.class, logger);
249: logger = null;
250: }
251: super .unload();
252: }
253:
254: // timer fired, see if we've found our servers
255: private void checkPings() {
256: synchronized (lock) {
257: if (logger.isDetailEnabled()) {
258: logger.detail("checkPings(), searching=" + searching
259: + ", selectAddr=" + selectAddr + ", foundAny="
260: + foundAny);
261: }
262: if (!searching) {
263: return;
264: }
265: // do we have at least one server?
266: if (selectAddr != null && foundAny) {
267: stopSearching();
268: return;
269: }
270: // keep searching
271: sendPings();
272: }
273: }
274:
275: private void startSearching() {
276: if (logger.isDetailEnabled()) {
277: logger.detail("startSearching(), searching=" + searching
278: + ", bootstrapService=" + bootstrapService
279: + ", pingService=" + pingService
280: + ", serversService=" + serversService);
281: }
282: if (searching) {
283: return;
284: }
285: if (logger.isInfoEnabled()) {
286: logger
287: .info("Starting bootstrap search, sending pings to servers["
288: + entries.size() + "]=" + entries.keySet());
289: }
290: searching = true;
291: if (bootstrapService != null) {
292: bootstrapService.startSearching();
293: }
294: // send pings to the servers we know about
295: sendPings();
296: }
297:
298: private void stopSearching() {
299: if (logger.isDetailEnabled()) {
300: logger.detail("stopSearching(), searching=" + searching
301: + ", bootstrapService=" + bootstrapService
302: + ", pingService=" + pingService
303: + ", serversService=" + serversService);
304: }
305: if (!searching) {
306: return;
307: }
308: searching = false;
309: if (logger.isInfoEnabled()) {
310: Set found = getServers(true);
311: Set unacked = getServers(false);
312: logger
313: .info("Stopping bootstrap search, found servers["
314: + found.size()
315: + "]="
316: + found
317: + (unacked.isEmpty() ? ""
318: : (", pings failed for servers["
319: + unacked.size() + "]=" + unacked)));
320: }
321: pingDeadline = -1;
322: foundAny = false;
323: if (bootstrapService != null) {
324: bootstrapService.stopSearching();
325: }
326: }
327:
328: private void sendPings() {
329: if (logger.isDetailEnabled()) {
330: logger.detail("sendPings(), pingService=" + pingService
331: + ", entries[" + entries.size() + "]=" + entries);
332: }
333: long now = System.currentTimeMillis();
334: pingDeadline = now + config.pingTimeout;
335: if (pingService == null) {
336: return;
337: }
338: checkPingsThread.schedule(config.pingTimeout);
339: int n = entries.size();
340: if (n <= 0) {
341: return;
342: }
343: Iterator iter = entries.entrySet().iterator();
344: for (int i = 0; i < n; i++) {
345: Map.Entry me = (Map.Entry) iter.next();
346: String name = (String) me.getKey();
347: Entry e = (Entry) me.getValue();
348: MessageAddress addr = e.getMessageAddress();
349: if (logger.isDebugEnabled()) {
350: logger.debug("Sending ping[" + i + " / " + n + "] to "
351: + addr);
352: }
353: pingService.ping(addr, pingDeadline);
354: }
355: }
356:
357: // receive a ping-ack.
358: // if it's our first server, makeSelection and tell our clients.
359: // wait for the timer to stopSearching, to allow more servers.
360: private void pingAnswer(MessageAddress addr, long rtt) {
361: if (logger.isDetailEnabled()) {
362: logger.detail("pingAnswer(" + addr + ", " + rtt + ")");
363: }
364: synchronized (lock) {
365: String s = addr.getAddress();
366: Entry e = (Entry) entries.get(s);
367: if (e == null) {
368: return;
369: }
370: if (e.getUpdateTime() <= 0 && logger.isInfoEnabled()) {
371: logger.info("Added white pages server " + addr
372: + " (rtt=" + rtt + ") to servers["
373: + entries.size() + "]=" + entries.keySet());
374: }
375: long now = System.currentTimeMillis();
376: e.reset((int) rtt, now);
377: if (!searching) {
378: return;
379: }
380: if (selectAddr != null && foundAny) {
381: // another server, keep searching
382: return;
383: }
384: makeSelection(now);
385: if (selectAddr == null) {
386: // server is bad?
387: return;
388: }
389: foundAny = true;
390: }
391: // now that we have a server, tell our clients
392: tellClients();
393: }
394:
395: // add a server.
396: // if we're searching, send a ping to it.
397: // wait for a ping-ack before stopSearching or makeSelection
398: private void addServer(MessageAddress addr) {
399: synchronized (lock) {
400: String s = addr.getAddress();
401: Entry e = (Entry) entries.get(s);
402: if (e != null) {
403: if (logger.isDetailEnabled()) {
404: logger.detail("already have server[" + addr + "]="
405: + e);
406: }
407: return;
408: }
409: e = new Entry(addr);
410: entries.put(s, e);
411: if (logger.isDebugEnabled()) {
412: logger
413: .debug("Added new server "
414: + addr
415: + ", "
416: + (searching ? ("sending ping " + (pingService == null ? "later"
417: : "now"))
418: : ("not sending ping since we're not searching")));
419: }
420: if (searching && pingService != null) {
421: if (logger.isDebugEnabled()) {
422: int n = entries.size();
423: logger.debug("Sending ping[" + (n - 1) + " / " + n
424: + "] to " + addr);
425: }
426: pingService.ping(addr, pingDeadline);
427: }
428: // log info "Added" when we get a ping-ack!
429: }
430: }
431:
432: // remove a server.
433: private void removeServer(MessageAddress addr) {
434: if (logger.isDebugEnabled()) {
435: logger.debug("Removing server " + addr);
436: }
437: synchronized (lock) {
438: String s = addr.getAddress();
439: if (entries.remove(s) == null) {
440: return;
441: }
442: clearSelection(addr);
443: // if searching, fix foundAny?
444: if (logger.isInfoEnabled()) {
445: logger.info("Removed white pages server " + addr
446: + " from servers[" + entries.size() + "]="
447: + entries.keySet());
448: }
449: return;
450: }
451: }
452:
453: private MessageAddress select(boolean lookup, String name) {
454: // select the entry with the min score
455: synchronized (lock) {
456: long now = System.currentTimeMillis();
457: if (now > selectTime) {
458: makeSelection(now);
459: }
460: if (selectAddr == null) {
461: return null;
462: }
463: long deadline = now + selectTimeout;
464: // round up the deadline for better memoizing
465: if (config.deadlineMod > 1) {
466: long mod = deadline % config.deadlineMod;
467: if (mod > 0) {
468: deadline += config.deadlineMod - mod;
469: }
470: }
471: MessageAddress target;
472: // memoize the target w/ deadline
473: if ((selectAddr == memoAddr) && (deadline == memoDeadline)) {
474: target = memoTarget;
475: } else {
476: target = MessageTimeoutUtils.setDeadline(selectAddr,
477: deadline);
478: memoAddr = selectAddr;
479: memoDeadline = deadline;
480: memoTarget = target;
481: }
482: return target;
483: }
484: }
485:
486: private void makeSelection(long now) {
487: selectTime = now + config.period;
488: int n = entries.size();
489: if (n <= 0) {
490: // no servers yet
491: selectAddr = null;
492: selectTimeout = 1; // unused
493: startSearching();
494: return;
495: }
496: // select the best server
497: Entry bestEntry;
498: double bestScore = 0.0;
499: Iterator iter = entries.entrySet().iterator();
500: if (n == 1) {
501: Map.Entry me = (Map.Entry) iter.next();
502: bestEntry = (Entry) me.getValue();
503: bestScore = computeScore(bestEntry, now);
504: } else {
505: bestEntry = null;
506: for (int i = 0; i < n; i++) {
507: Map.Entry me = (Map.Entry) iter.next();
508: Entry e = (Entry) me.getValue();
509: double score = computeScore(e, now);
510: if (i == 0 || score < bestScore) {
511: bestEntry = e;
512: bestScore = score;
513: }
514: }
515: }
516: // if all servers are lousy, start searching for new ones
517: if (bestScore >= config.lousyScore) {
518: startSearching();
519: }
520: // attach timeout
521: int timeout = bestEntry.getTimeout();
522: if (timeout == 0) {
523: timeout = config.defaultTimeout;
524: } else if (timeout <= config.minTimeout) {
525: timeout = config.minTimeout;
526: } else if (config.maxTimeout < timeout) {
527: timeout = config.maxTimeout;
528: }
529: MessageAddress addr = bestEntry.getMessageAddress();
530: if (logger.isInfoEnabled()) {
531: if (selectAddr == null
532: || !selectAddr.getAddress().equals(
533: addr.getAddress())) {
534: logger.info("Selected server "
535: + bestEntry.toString(now) + " with timeout "
536: + timeout + " and score " + bestScore
537: + ", prior selection was " + selectAddr);
538: } else if (logger.isDebugEnabled()) {
539: logger.debug("Keeping server "
540: + bestEntry.toString(now) + " with timeout "
541: + timeout + " and score " + bestScore);
542: }
543: }
544: selectTimeout = timeout;
545: selectAddr = addr;
546: }
547:
548: /**
549: */
550: private double computeScore(Entry e, long now) {
551: // assert (Thread.holdsLock(lock));
552: double ret = (e.getUpdateTime() > 0 ? ((double) e.getAverage())
553: : config.initialScore);
554: // favor primary server by adjusting its score
555: boolean isPrimary = (config.primaryAddress != null && config.primaryAddress
556: .equals(e.getMessageAddress().getAddress()));
557: if (isPrimary) {
558: ret *= config.primaryWeight;
559: }
560: if (logger.isDebugEnabled()) {
561: logger.debug("Score is " + ret + " for " + e.toString(now));
562: }
563: return ret;
564: }
565:
566: /** clear the memoized selection if it matches the passed address */
567: private void clearSelection(MessageAddress addr) {
568: // assert (Thread.holdsLock(lock));
569: if (selectAddr == null || addr == null
570: || (!selectAddr.getAddress().equals(addr.getAddress()))) {
571: return;
572: }
573: selectTime = 0;
574: selectAddr = null;
575: }
576:
577: /**
578: * Update an entry score based upon measured performance.
579: */
580: private void update(Entry e, long rtt, boolean timeout, long now) {
581: // assert (Thread.holdsLock(lock));
582: e.update((int) rtt, now);
583: if (logger.isDetailEnabled()) {
584: logger.detail("updated entry with "
585: + (timeout ? "timeout" : "success") + " rtt=" + rtt
586: + ": " + e.toString(now));
587: }
588: // force re-select if this is our selectAddr and it's bad now?
589: }
590:
591: //
592: // the rest is fairly straight-forward...
593: //
594:
595: private void register(SelectService.Client c) {
596: selectClients.add(c);
597: }
598:
599: private void unregister(SelectService.Client c) {
600: selectClients.remove(c);
601: }
602:
603: private void tellClients() {
604: List cl = selectClients.getUnmodifiableList();
605: for (int i = 0, ln = cl.size(); i < ln; i++) {
606: SelectService.Client c = (SelectService.Client) cl.get(i);
607: c.onChange();
608: }
609: }
610:
611: private boolean contains(MessageAddress addr) {
612: synchronized (lock) {
613: String s = addr.getAddress();
614: return entries.containsKey(s);
615: }
616: }
617:
618: private void update(MessageAddress addr, long rtt, boolean timeout) {
619: synchronized (lock) {
620: String s = addr.getAddress();
621: Entry e = (Entry) entries.get(s);
622: if (e != null) {
623: long now = System.currentTimeMillis();
624: update(e, rtt, timeout, now);
625: }
626: }
627: }
628:
629: private Set getServers(boolean acked) {
630: // assert (Thread.holdsLock(lock));
631: Set ret = Collections.EMPTY_SET;
632: for (Iterator iter = entries.entrySet().iterator(); iter
633: .hasNext();) {
634: Map.Entry me = (Map.Entry) iter.next();
635: String name = (String) me.getKey();
636: Entry e = (Entry) me.getValue();
637: if (acked != e.getUpdateTime() > 0) {
638: continue;
639: }
640: if (ret.isEmpty()) {
641: ret = new HashSet();
642: }
643: ret.add(name);
644: }
645: return ret;
646: }
647:
648: private String my_toString() {
649: synchronized (lock) {
650: return "(servers=" + entries.toString() + ")";
651: }
652: }
653:
654: /**
655: * An entry monitors the performance for a single server.
656: */
657: private static class Entry {
658:
659: // alpha for average updates is 1/8
660: private static final int GAIN_AVG = 3;
661:
662: // use a larger alpha for stdDev weight: 1/4
663: private static final int GAIN_VAR = 2;
664:
665: // the timeout quartile is the same as the GAIN_VAR
666:
667: private final MessageAddress addr;
668: private long updateTime;
669:
670: /** @see update */
671: private int sa;
672: private int sv;
673: private int rto;
674:
675: public Entry(MessageAddress addr) {
676: this .addr = addr;
677: //
678: String s = (addr == null ? "null addr" : null);
679: if (s != null) {
680: throw new IllegalArgumentException(s);
681: }
682: }
683:
684: public void reset(int rtt, long now) {
685: updateTime = now;
686: sa = rtt << GAIN_AVG;
687: sv = 0;
688: rto = rtt;
689: }
690:
691: /**
692: * Update our rtt average and std-dev.
693: * <p>
694: * For math see <i>Jacobson88</i>, sec2, appendix A. This is
695: * the standard TCP rtt-based timeout smoothing algorithm.
696: *
697: * @param rtt the measured round-trip-time
698: * @param now the current time
699: */
700: public void update(int rtt, long now) {
701: if (updateTime <= 0) {
702: reset(rtt, now);
703: return;
704: }
705: updateTime = now;
706: int m = rtt;
707: m -= (sa >> GAIN_AVG);
708: sa += m;
709: if (m < 0) {
710: m = -m;
711: }
712: m -= (sv >> GAIN_VAR);
713: sv += m;
714: rto = (sa >> GAIN_AVG) + sv;
715: }
716:
717: /** @return the time of the most recent update */
718: public long getUpdateTime() {
719: return updateTime;
720: }
721:
722: /** @return the average round-trip-time */
723: public int getAverage() {
724: return sa >> GAIN_AVG;
725: }
726:
727: /** @return the std-dev of the round-trip-time */
728: public int getStdDev() {
729: return sv >> GAIN_VAR;
730: }
731:
732: /**
733: * @return the proposed timeout, ignoring any decay based
734: * upon the age of the update time.
735: */
736: public int getTimeout() {
737: return rto;
738: }
739:
740: public MessageAddress getMessageAddress() {
741: return addr;
742: }
743:
744: public String toString() {
745: long now = System.currentTimeMillis();
746: return toString(now);
747: }
748:
749: public String toString(long now) {
750: return "(server address=" + addr + " updateTime="
751: + Timestamp.toString(getUpdateTime(), now)
752: + " average=" + getAverage() + " stdDev="
753: + getStdDev() + " timeout=" + getTimeout() + ")";
754: }
755: }
756:
757: private class SelectSP extends ServiceProviderBase {
758: protected void register(Object client) {
759: SelectManager.this .register((SelectService.Client) client);
760: }
761:
762: protected void unregister(Object client) {
763: SelectManager.this
764: .unregister((SelectService.Client) client);
765: }
766:
767: protected Class getServiceClass() {
768: return SelectService.class;
769: }
770:
771: protected Class getClientClass() {
772: return SelectService.Client.class;
773: }
774:
775: protected Service getService(Object client) {
776: return new SI(client);
777: }
778:
779: protected class SI extends MyServiceImpl implements
780: SelectService {
781: public SI(Object client) {
782: super (client);
783: }
784:
785: public boolean contains(MessageAddress addr) {
786: return SelectManager.this .contains(addr);
787: }
788:
789: public MessageAddress select(boolean lookup, String name) {
790: return SelectManager.this .select(lookup, name);
791: }
792:
793: public void update(MessageAddress addr, long duration,
794: boolean timeout) {
795: SelectManager.this .update(addr, duration, timeout);
796: }
797:
798: public String toString() {
799: return SelectManager.this .my_toString();
800: }
801: }
802: }
803:
804: /** config options */
805: private static class SelectManagerConfig {
806: public final long period;
807: public final long deadlineMod;
808: public final int minTimeout;
809: public final int defaultTimeout;
810: public final int maxTimeout;
811: public final String primaryAddress;
812: public final double primaryWeight;
813: public final long pingTimeout;
814: public final double initialScore;
815: public final double lousyScore;
816:
817: public SelectManagerConfig(Object o) {
818: Parameters p = new Parameters(o,
819: "org.cougaar.core.wp.resolver.select.");
820: period = p.getLong("period", 30000);
821: deadlineMod = p.getLong("deadlineMod", 25);
822: minTimeout = p.getInt("minTimeout", 3000);
823: defaultTimeout = p.getInt("defaultTimeout", 20000);
824: maxTimeout = p.getInt("maxTimeout", 120000);
825: String s = p.getString("primary");
826: // in form "alias(:addr)?", extract "addr" suffix
827: int idx = (s == null ? -1 : s.indexOf(':'));
828: primaryAddress = (idx <= 0 ? s : s.substring(idx + 1));
829: double d = p.getDouble("favorPrimaryBy", 0.0);
830: d = 1.0 - d;
831: if (d > 1.0) {
832: d = 1.0;
833: } else if (d < 0.0) {
834: d = 0.0;
835: }
836: primaryWeight = d;
837: pingTimeout = p.getLong("pingTimeout", 30000);
838: double defaultScore = p.getDouble("defaultScore", 750.0);
839: d = Math.max(defaultScore, (double) (pingTimeout + 10000));
840: initialScore = p.getDouble("initialScore", d);
841: d = Math.max(defaultScore, 3000.0);
842: lousyScore = p.getDouble("lousyScore", d);
843: }
844: }
845: }
|