001: /*
002: * <copyright>
003: *
004: * Copyright 1997-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.agent;
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.Map;
034: import java.util.Set;
035: import org.cougaar.bootstrap.SystemProperties;
036: import org.cougaar.core.agent.service.MessageSwitchService;
037: import org.cougaar.core.agent.service.alarm.Alarm;
038: import org.cougaar.core.agent.service.alarm.ExecutionTimer;
039: import org.cougaar.core.component.Component;
040: import org.cougaar.core.component.ServiceBroker;
041: import org.cougaar.core.component.ServiceProvider;
042: import org.cougaar.core.component.ServiceRevokedListener;
043: import org.cougaar.core.logging.LoggingServiceWithPrefix;
044: import org.cougaar.core.mts.Message;
045: import org.cougaar.core.mts.MessageAddress;
046: import org.cougaar.core.mts.MessageHandler;
047: import org.cougaar.core.node.NodeIdentificationService;
048: import org.cougaar.core.node.service.NaturalTimeService;
049: import org.cougaar.core.service.AgentIdentificationService;
050: import org.cougaar.core.service.DemoControlService;
051: import org.cougaar.core.service.LoggingService;
052: import org.cougaar.core.service.UIDService;
053: import org.cougaar.core.service.wp.WhitePagesService;
054: import org.cougaar.core.thread.SchedulableStatus;
055: import org.cougaar.core.wp.ListAllNodes;
056: import org.cougaar.core.util.UID;
057: import org.cougaar.util.GenericStateModelAdapter;
058:
059: /**
060: * This component adds the agent's {@link DemoControlService}.
061: * <p>
062: * This implementation uses the {@link MessageSwitchService} to
063: * send the society time-advance requests to other nodes. Other
064: * implementation options included blackboard relays (but blackboard
065: * transactions could complicate matters) and servlets (but more
066: * difficult to achieve parallelism).
067: *
068: * @property org.cougaar.core.agent.demoControl.namingTimeout
069: * Timeout in milliseconds for a DemoControlService setSocietyTime
070: * lookup of all target nodes in the naming service. Defaults to
071: * 30000 millis.
072: */
073: public class DemoControl extends GenericStateModelAdapter implements
074: Component {
075:
076: private static final long NAMING_LOOKUP_TIMEOUT = SystemProperties
077: .getLong(
078: "org.cougaar.core.agent.demoControl.namingTimeout",
079: 30000);
080:
081: private static final Long PENDING = new Long(-1);
082:
083: protected ServiceBroker sb;
084:
085: protected LoggingService log;
086: protected MessageAddress localAgent;
087: protected MessageAddress localNode;
088: protected WhitePagesService wp;
089:
090: private NaturalTimeService xTimer;
091: private UIDService uidService;
092: private MessageSwitchService mss;
093:
094: private final Object lock = new Object();
095: private final Map table = new HashMap(3);
096:
097: private ServiceProvider dcsp;
098:
099: public void setServiceBroker(ServiceBroker sb) {
100: this .sb = sb;
101: }
102:
103: public void load() {
104: super .load();
105:
106: localAgent = find_local_agent();
107: localNode = find_local_node();
108:
109: log = (LoggingService) sb.getService(this ,
110: LoggingService.class, null);
111: log = LoggingServiceWithPrefix.add(log, localAgent + ": ");
112:
113: // get execution timer
114: xTimer = (NaturalTimeService) sb.getService(this ,
115: NaturalTimeService.class, null);
116: if (xTimer == null) {
117: throw new RuntimeException(
118: "Unable to obtain NaturalTimeService");
119: }
120:
121: uidService = (UIDService) sb.getService(this , UIDService.class,
122: null);
123: if (uidService == null) {
124: throw new RuntimeException("Unable to obtain UIDService");
125: }
126:
127: wp = (WhitePagesService) sb.getService(this ,
128: WhitePagesService.class, null);
129: if (wp == null) {
130: throw new RuntimeException(
131: "Unable to obtain WhitePagesService");
132: }
133:
134: mss = (MessageSwitchService) sb.getService(this ,
135: MessageSwitchService.class, null);
136: if (mss == null) {
137: throw new RuntimeException(
138: "Unable to obtain MessageSwitchService");
139: }
140:
141: // register message handler for DemoControlMessages
142: MessageHandler mh = new MessageHandler() {
143: public boolean handleMessage(Message message) {
144: if (message instanceof DemoControlMessage) {
145: receiveLater((DemoControlMessage) message);
146: return true;
147: } else {
148: return false;
149: }
150: }
151: };
152: mss.addMessageHandler(mh);
153:
154: // add demo control
155: dcsp = new DemoControlSP();
156: sb.addService(DemoControlService.class, dcsp);
157: }
158:
159: public void unload() {
160: super .unload();
161:
162: sb.revokeService(DemoControlService.class, dcsp);
163: dcsp = null;
164:
165: if (mss != null) {
166: // mss.unregister?
167: sb.releaseService(this , MessageSwitchService.class, mss);
168: mss = null;
169: }
170:
171: if (uidService != null) {
172: sb.releaseService(this , UIDService.class, uidService);
173: uidService = null;
174: }
175:
176: if (wp != null) {
177: sb.releaseService(this , WhitePagesService.class, wp);
178: wp = null;
179: }
180:
181: if (xTimer != null) {
182: sb.releaseService(this , NaturalTimeService.class, xTimer);
183: xTimer = null;
184: }
185:
186: if (log != null) {
187: sb.releaseService(this , LoggingService.class, log);
188: log = null;
189: }
190: }
191:
192: /**
193: * Get the set of all node names in the society.
194: * <p>
195: * This method is <tt>protected</tt> to allow a subclass to specify
196: * an alternate implementation, e.g.:<ul>
197: * <li>read a config file or external authority</li>
198: * <li>return a partial list for a split society</li>
199: * <li>return just the agents that share the same execution
200: * time as this agent, in case agents in the same society
201: * or even node have different execution clocks</li>
202: * <li>etc</li>
203: * </ul>
204: */
205: protected Set getSocietyTargets() {
206: Set names;
207: try {
208: names = ListAllNodes
209: .listAllNodes(wp, NAMING_LOOKUP_TIMEOUT);
210: } catch (Exception e) {
211: log.warn("Unable to listAllNodes", e);
212: names = null;
213: }
214: boolean hasLocalNode = false;
215: Set ret;
216: int n = (names == null ? 0 : names.size());
217: if (n == 0) {
218: ret = Collections.EMPTY_SET;
219: } else {
220: ret = new HashSet(n);
221: Iterator iter = names.iterator();
222: for (int i = 0; i < n; i++) {
223: String s = (String) iter.next();
224: MessageAddress addr = MessageAddress
225: .getMessageAddress(s);
226: if (localNode.equals(addr)) {
227: hasLocalNode = true;
228: }
229: ret.add(addr);
230: }
231: }
232: if (!hasLocalNode) {
233: if (log.isWarnEnabled()) {
234: log
235: .warn("Society node list["
236: + ret.size()
237: + "] from the naming"
238: + " service lacks local node "
239: + localNode
240: + ", adding it to"
241: + " the list, but note that this suggests that other"
242: + " nodes may be missing from the list! "
243: + ret);
244: }
245: if (ret.isEmpty()) {
246: ret = Collections.singleton(localNode);
247: } else {
248: ret.add(localNode);
249: }
250: }
251: if (log.isInfoEnabled()) {
252: log.info("WP lookup found nodes[" + n + "]=" + ret);
253: }
254: return ret;
255: }
256:
257: //
258: // the rest is private!
259: //
260:
261: private MessageAddress find_local_agent() {
262: AgentIdentificationService ais = (AgentIdentificationService) sb
263: .getService(this , AgentIdentificationService.class,
264: null);
265: if (ais == null) {
266: return null;
267: }
268: MessageAddress ret = ais.getMessageAddress();
269: sb.releaseService(this , AgentIdentificationService.class, ais);
270: return ret;
271: }
272:
273: private MessageAddress find_local_node() {
274: NodeIdentificationService nis = (NodeIdentificationService) sb
275: .getService(this , NodeIdentificationService.class, null);
276: if (nis == null) {
277: return null;
278: }
279: MessageAddress ret = nis.getMessageAddress();
280: sb.releaseService(this , NodeIdentificationService.class, nis);
281: return ret;
282: }
283:
284: private void setLocalTime(long offset, double rate, long changeTime) {
285: ExecutionTimer.Parameters p = new ExecutionTimer.Parameters(
286: rate, offset, changeTime);
287: if (log.isInfoEnabled()) {
288: log.info("setSocietyTime(p=" + p + ")");
289: }
290: xTimer.setParameters(p);
291: }
292:
293: private boolean setSocietyTime(long offset, double rate,
294: long changeTime, Set targets, long timeout) {
295: // submit async request
296: BlockingCallback bcb = new BlockingCallback();
297: long startTime = System.currentTimeMillis();
298: setSocietyTime(offset, rate, changeTime, targets, bcb);
299: // block for the answer
300: boolean ret = bcb.waitForIsComplete(timeout);
301: if (!ret && log.isWarnEnabled()) {
302: log.warn("Interrupted setSocietyTime(" + offset + ", "
303: + rate + ", " + changeTime + ") after "
304: + (System.currentTimeMillis() - startTime)
305: + " millis, did not receive all \"acks\" yet!");
306: }
307: return ret;
308: }
309:
310: private boolean setSocietyTime(long offset, double rate,
311: long changeTime, Set targets, DemoControlService.Callback cb) {
312: ExecutionTimer.Parameters p = new ExecutionTimer.Parameters(
313: rate, offset, changeTime);
314: int n = (targets == null ? 0 : targets.size());
315: if (log.isInfoEnabled()) {
316: log.info("setSocietyTime(p=" + p + ", targets[" + n
317: + "], cb=" + cb + ")");
318: }
319: // make sure our local node is listed, otherwise the naming
320: // service likely contains partial data. We want to set the
321: // time on *all* nodes.
322: Map m = new HashMap(n);
323: boolean hasLocalAgent = false;
324: if (n > 0) {
325: Iterator iter = targets.iterator();
326: for (int i = 0; i < n; i++) {
327: MessageAddress addr = (MessageAddress) iter.next();
328: MessageAddress key = addr.getPrimary();
329: Object value;
330: if (localAgent.equals(key)) {
331: hasLocalAgent = true;
332: value = new Long(0);
333: } else {
334: value = PENDING;
335: }
336: m.put(key, value);
337: }
338: }
339: if (cb != null) {
340: cb.sendingTimeAdvanceTo(Collections.unmodifiableSet(m
341: .keySet()));
342: }
343: if (n == 1 && hasLocalAgent) {
344: if (log.isInfoEnabled()) {
345: log
346: .info("Just setting local agent's time to "
347: + p
348: + (cb == null ? ""
349: : ", then invoking callback"));
350: }
351: // just local agent
352: setLocalTime(offset, rate, changeTime);
353: if (cb != null) {
354: cb.updatedTime(localAgent, 0);
355: m = Collections.singletonMap(localAgent, new Long(0));
356: cb.completed(m);
357: }
358: return true;
359: }
360: // choose change_time that's better than the default:
361: // NaturalTimeService.DEFAULT_CHANGE_DELAY
362: /*
363: long now = System.currentTimeMillis();
364: long change_time =
365: now +
366: 10000 +
367: (targets.size() >> 1);
368: */
369: // FIXME modify p with change_time?
370: // set local node's time
371: if (hasLocalAgent) {
372: setLocalTime(offset, rate, changeTime);
373: }
374: UID uid = uidService.nextUID();
375: synchronized (lock) {
376: Entry e = new Entry();
377: table.put(uid, e);
378: e.setMap(m);
379: e.setPendingCount(n - (hasLocalAgent ? 1 : 0));
380: e.setCallback(cb);
381: e.setSendTime(System.currentTimeMillis());
382: }
383: // send messages
384: if (log.isInfoEnabled()) {
385: log.info("Sending messages (uid=" + uid + ", p=" + p
386: + ") to targets[" + n + "]=" + targets);
387: }
388: Iterator iter = targets.iterator();
389: for (int i = 0; i < n; i++) {
390: MessageAddress addr = (MessageAddress) iter.next();
391: MessageAddress key = addr.getPrimary();
392: if (localAgent.equals(key)) {
393: continue;
394: }
395: DemoControlMessage dcm = new DemoControlMessage(localAgent,
396: addr, uid, p, false);
397: mss.sendMessage(dcm);
398: }
399: return false;
400: }
401:
402: private void receiveLater(DemoControlMessage dcm) {
403: // we could put this on a queue and "thread.start()", to avoid
404: // blocking the MTS, but xTimer shouldn't block, so we'll process
405: // this message in the MTS thread.
406: receiveNow(dcm);
407: }
408:
409: private void receiveNow(DemoControlMessage dcm) {
410: if (log.isDebugEnabled()) {
411: log.debug("receiveNow(" + dcm + ")");
412: }
413: MessageAddress sender = dcm.getOriginator();
414: if (sender.equals(localAgent)) {
415: if (log.isWarnEnabled()) {
416: log.warn("Ignoring message from self: " + dcm);
417: }
418: return;
419: }
420: if (!dcm.isAck()) {
421: // client
422: receiveAdvanceRequest(dcm);
423: return;
424: }
425: // server
426: receiveAck(dcm);
427: }
428:
429: private void receiveAdvanceRequest(DemoControlMessage dcm) {
430: // receive request to set our time, sent back ack
431: MessageAddress sender = dcm.getOriginator();
432: UID uid = dcm.getUID();
433: ExecutionTimer.Parameters p = dcm.getParameters();
434: if (log.isInfoEnabled()) {
435: log.info("Accepting " + sender + " request uid=" + uid
436: + " to set local node's time to " + p
437: + ", will send ack message");
438: }
439: // remote request to setLocalTime
440: setLocalTime(p.theOffset, p.theRate, p.theChangeTime);
441: // send ack back to sender
442: DemoControlMessage ack_dcm = new DemoControlMessage(localAgent,
443: sender, uid, null, true);
444: mss.sendMessage(ack_dcm);
445: }
446:
447: private void receiveAck(DemoControlMessage dcm) {
448: // receive ack, make sure we sent it
449: MessageAddress sender = dcm.getOriginator();
450: UID uid = dcm.getUID();
451: ExecutionTimer.Parameters p = dcm.getParameters();
452: DemoControlService.Callback cb;
453: Object result;
454: long rtt;
455: Map resultMap;
456: synchronized (lock) {
457: Entry e = (Entry) table.get(uid);
458: if (e == null) {
459: if (log.isWarnEnabled()) {
460: log.warn("Ignoring unknown ack uid=" + uid
461: + ", msg=" + dcm);
462: }
463: return;
464: }
465: Map m = e.getMap();
466: MessageAddress key = sender.getPrimary();
467: Object o = m.get(key);
468: if (o != PENDING) {
469: if (log.isDebugEnabled()) {
470: log.debug("Ignoring "
471: + (o == null ? "Unknown" : "Duplicate(" + o
472: + ")") + " ack sender=" + key
473: + ", msg=" + dcm + ", targets[" + m.size()
474: + "]=" + m.keySet());
475: }
476: return;
477: }
478: rtt = System.currentTimeMillis() - e.getSendTime();
479: int pendingCount = e.getPendingCount();
480: if (log.isInfoEnabled()) {
481: log.info(" received uid=" + uid + " ack["
482: + (m.size() - pendingCount) + " / " + m.size()
483: + "] target=" + key + " rtt=" + rtt);
484: }
485: m.put(key, new Long(rtt));
486: pendingCount--;
487: e.setPendingCount(pendingCount);
488: cb = e.getCallback();
489: if (pendingCount <= 0) {
490: // all acks are in
491: if (log.isInfoEnabled()) {
492: log
493: .info("Received all acks["
494: + m.size()
495: + "]"
496: + ", rtt="
497: + rtt
498: + (cb == null ? ""
499: : ", invoking callback"));
500: }
501: table.remove(key);
502: }
503: if (cb == null) {
504: return;
505: }
506: if (pendingCount > 0) {
507: // still more pending
508: resultMap = null;
509: } else {
510: // callback data is map<addr, rtt>
511: resultMap = Collections.unmodifiableMap(m);
512: }
513: }
514: cb.updatedTime(sender.getPrimary(), rtt);
515: if (resultMap != null) {
516: cb.completed(resultMap);
517: }
518: }
519:
520: private static class Entry {
521: private Map m;
522: private int n;
523: private DemoControlService.Callback cb;
524: private long sendTime;
525:
526: public Map getMap() {
527: return m;
528: }
529:
530: public void setMap(Map m) {
531: this .m = m;
532: }
533:
534: public int getPendingCount() {
535: return n;
536: }
537:
538: public void setPendingCount(int n) {
539: this .n = n;
540: }
541:
542: public DemoControlService.Callback getCallback() {
543: return cb;
544: }
545:
546: public void setCallback(DemoControlService.Callback cb) {
547: this .cb = cb;
548: }
549:
550: public long getSendTime() {
551: return sendTime;
552: }
553:
554: public void setSendTime(long sendTime) {
555: this .sendTime = sendTime;
556: }
557:
558: public String toString() {
559: return "(entry sentTime=" + sendTime + " n=" + n + " m="
560: + m + " cb=" + cb + ")";
561: }
562: }
563:
564: /**
565: * Simple DemoControlService.Callback that blocks the
566: * <tt>completed</tt> call.
567: */
568: private static class BlockingCallback implements
569: DemoControlService.Callback {
570: private final Object lock = new Object();
571: private boolean isComplete = false;
572:
573: public boolean isComplete() {
574: synchronized (lock) {
575: return isComplete;
576: }
577: }
578:
579: public boolean waitForIsComplete(long millis) {
580: synchronized (lock) {
581: if (isComplete) {
582: return true;
583: }
584: try {
585: SchedulableStatus.beginWait("society time advance");
586: lock.wait(millis);
587: } catch (InterruptedException ie) {
588: return isComplete; // make PMD happy
589: } finally {
590: SchedulableStatus.endBlocking();
591: }
592: return isComplete;
593: }
594: }
595:
596: public void sendingTimeAdvanceTo(Set addrs) {
597: }
598:
599: public void updatedTime(MessageAddress addr, long rtt) {
600: }
601:
602: public void completed(Map m) {
603: synchronized (lock) {
604: isComplete = true;
605: lock.notifyAll();
606: }
607: }
608: }
609:
610: private class DemoControlSP implements ServiceProvider {
611: private final DemoControlService SERVICE_INSTANCE = new DemoControlSI();
612:
613: public Object getService(ServiceBroker sb, Object requestor,
614: Class serviceClass) {
615: if (DemoControlService.class.isAssignableFrom(serviceClass)) {
616: return SERVICE_INSTANCE;
617: } else {
618: return null;
619: }
620: }
621:
622: public void releaseService(ServiceBroker sb, Object requestor,
623: Class serviceClass, Object service) {
624: }
625: }
626:
627: private final class DemoControlSI implements DemoControlService {
628: // alarm service:
629: private void die() {
630: throw new UnsupportedOperationException();
631: }
632:
633: public long currentTimeMillis() {
634: die();
635: return -1;
636: }
637:
638: public void addAlarm(Alarm alarm) {
639: die();
640: }
641:
642: public void addRealTimeAlarm(Alarm alarm) {
643: die();
644: }
645:
646: // demo service:
647: public double getExecutionRate() {
648: return xTimer.getRate();
649: }
650:
651: public void setLocalTime(long offset, double newRate,
652: long changeTime) {
653: DemoControl.this .setLocalTime(offset, newRate, changeTime);
654: }
655:
656: public void setNodeTime(long time, double newRate,
657: long changeTime) {
658: setNodeTime(time, true, newRate, false, changeTime, true);
659: }
660:
661: public void advanceNodeTime(long timePeriod, double newRate) {
662: setNodeTime(timePeriod, false, newRate, false,
663: NaturalTimeService.DEFAULT_CHANGE_DELAY, false);
664: }
665:
666: public void setNodeTime(long time, double newRate) {
667: setNodeTime(time, true, newRate, false,
668: NaturalTimeService.DEFAULT_CHANGE_DELAY, true);
669: }
670:
671: private void setNodeTime(long millis, boolean millisIsAbsolute,
672: double newRate, boolean forceRunning, long changeDelay,
673: boolean changeIsAbsolute) {
674: ExecutionTimer.Parameters p = createParameters(millis,
675: millisIsAbsolute, newRate, forceRunning,
676: changeDelay, changeIsAbsolute);
677: DemoControl.this .setLocalTime(p.theOffset, p.theRate,
678: p.theChangeTime);
679: }
680:
681: private ExecutionTimer.Parameters createParameters(long millis,
682: boolean millisIsAbsolute, double newRate,
683: boolean forceRunning, long changeDelay,
684: boolean changeIsAbsolute) {
685: return xTimer.createParameters(millis, millisIsAbsolute,
686: newRate, forceRunning, changeDelay,
687: changeIsAbsolute);
688: }
689:
690: public boolean setSocietyTime(long offset, double rate,
691: long changeTime, Set targets, Callback cb) {
692: return DemoControl.this .setSocietyTime(offset, rate,
693: changeTime, targets, cb);
694: }
695:
696: public boolean setSocietyTime(long offset, double rate,
697: long changeTime, DemoControlService.Callback cb) {
698: return setSocietyTime(offset, rate, changeTime,
699: getSocietyTargets(), cb);
700: }
701:
702: public boolean setSocietyTime(long offset, double rate,
703: long changeTime, Set targets, long timeout) {
704: return DemoControl.this .setSocietyTime(offset, rate,
705: changeTime, targets, timeout);
706: }
707:
708: public boolean setSocietyTime(long offset, double rate,
709: long changeTime, long timeout) {
710: return setSocietyTime(offset, rate, changeTime,
711: getSocietyTargets(), timeout);
712: }
713:
714: public boolean setSocietyTime(long offset, double rate,
715: long changeTime) {
716: return setSocietyTime(offset, rate, changeTime,
717: getSocietyTargets(), changeTime);
718: }
719:
720: public void setSocietyTime(long time) {
721: setSocietyTime(time, true, 0.0, false,
722: NaturalTimeService.DEFAULT_CHANGE_DELAY, false);
723: }
724:
725: public void setSocietyTime(long time, boolean running) {
726: setSocietyTime(time, true, 0.0, running,
727: NaturalTimeService.DEFAULT_CHANGE_DELAY, false);
728: }
729:
730: public void setSocietyTimeRate(double newRate) {
731: setSocietyTime(0L, false, newRate, false,
732: NaturalTimeService.DEFAULT_CHANGE_DELAY, false);
733: }
734:
735: public void advanceSocietyTime(long timePeriod) {
736: setSocietyTime(timePeriod, false, 0.0, false,
737: NaturalTimeService.DEFAULT_CHANGE_DELAY, false);
738: }
739:
740: public void advanceSocietyTime(long timePeriod, boolean running) {
741: setSocietyTime(timePeriod, false, 0.0, running,
742: NaturalTimeService.DEFAULT_CHANGE_DELAY, false);
743: }
744:
745: public void advanceSocietyTime(long timePeriod, double newRate) {
746: setSocietyTime(timePeriod, false, newRate, false,
747: NaturalTimeService.DEFAULT_CHANGE_DELAY, false);
748: }
749:
750: public void advanceSocietyTime(ExecutionTimer.Change[] changes) {
751: ExecutionTimer.Parameters[] params = xTimer
752: .createParameters(changes);
753: for (int i = 0; i < params.length; i++) {
754: ExecutionTimer.Parameters p = params[i];
755: setSocietyTime(p.theOffset, p.theRate, p.theChangeTime);
756: }
757: }
758:
759: private void setSocietyTime(long millis,
760: boolean millisIsAbsolute, double newRate,
761: boolean forceRunning, long changeDelay,
762: boolean changeIsAbsolute) {
763: ExecutionTimer.Parameters p = createParameters(millis,
764: millisIsAbsolute, newRate, forceRunning,
765: changeDelay, changeIsAbsolute);
766: setSocietyTime(p.theOffset, p.theRate, p.theChangeTime);
767: }
768: }
769: }
|