0001: /*
0002: * <copyright>
0003: *
0004: * Copyright 1997-2004 BBNT Solutions, LLC
0005: * under sponsorship of the Defense Advanced Research Projects
0006: * Agency (DARPA).
0007: *
0008: * You can redistribute this software and/or modify it under the
0009: * terms of the Cougaar Open Source License as published on the
0010: * Cougaar Open Source Website (www.cougaar.org).
0011: *
0012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0023: *
0024: * </copyright>
0025: */
0026:
0027: package org.cougaar.planning.plugin.legacy;
0028:
0029: import java.util.Collection;
0030: import java.util.Date;
0031: import java.util.Enumeration;
0032: import java.util.Vector;
0033: import java.util.List;
0034:
0035: import org.cougaar.core.agent.service.alarm.Alarm;
0036: import org.cougaar.core.agent.service.alarm.ExecutionTimer;
0037: import org.cougaar.core.blackboard.BlackboardClient;
0038: import org.cougaar.core.blackboard.Claimable;
0039: import org.cougaar.core.blackboard.SubscriberException;
0040: import org.cougaar.core.blackboard.Subscription;
0041: import org.cougaar.core.blackboard.SubscriptionWatcher;
0042: import org.cougaar.core.component.BindingSite;
0043: import org.cougaar.core.component.Component;
0044: import org.cougaar.core.component.ServiceBroker;
0045: import org.cougaar.core.domain.Factory;
0046: import org.cougaar.core.mts.MessageAddress;
0047: import org.cougaar.core.plugin.PluginBase;
0048: import org.cougaar.core.service.AgentIdentificationService;
0049: import org.cougaar.core.service.AlarmService;
0050: import org.cougaar.core.service.BlackboardService;
0051: import org.cougaar.core.service.DemoControlService;
0052: import org.cougaar.core.service.DomainService;
0053: import org.cougaar.core.service.SchedulerService;
0054: import org.cougaar.core.service.UIDServer;
0055: import org.cougaar.core.service.UIDService;
0056: import org.cougaar.planning.ldm.ClusterServesPlugin;
0057: import org.cougaar.planning.ldm.LDMServesPlugin;
0058: import org.cougaar.planning.ldm.LatePropertyProvider;
0059: import org.cougaar.planning.ldm.PlanningFactory;
0060: import org.cougaar.planning.ldm.PropertyProvider;
0061: import org.cougaar.planning.ldm.PrototypeProvider;
0062: import org.cougaar.planning.service.LDMService;
0063: import org.cougaar.planning.service.PrototypeRegistryService;
0064: import org.cougaar.util.ConfigFinder;
0065: import org.cougaar.util.GenericStateModel;
0066: import org.cougaar.util.GenericStateModelAdapter;
0067: import org.cougaar.util.StateModelException;
0068: import org.cougaar.util.SyncTriggerModelImpl;
0069: import org.cougaar.util.Trigger;
0070: import org.cougaar.util.TriggerModel;
0071: import org.cougaar.util.UnaryPredicate;
0072:
0073: public abstract class PluginAdapter extends GenericStateModelAdapter
0074: implements PluginStateModel, Component, BlackboardClient,
0075: PluginBase {
0076: /** minimum time (in millis) which wake functions like to pause for **/
0077: public final static long WAKE_LATENCY = 1000L;
0078:
0079: /** keep this around for compatability with old plugins **/
0080: protected PlanningFactory theLDMF = null;
0081:
0082: protected LDMServesPlugin theLDM = null;
0083:
0084: //
0085: // constructor
0086: //
0087:
0088: public PluginAdapter() {
0089: }
0090:
0091: private PluginBindingSite bindingSite = null;
0092:
0093: public final void setBindingSite(final BindingSite bs) {
0094: this .bindingSite = new PluginBindingSite() {
0095: public MessageAddress getAgentIdentifier() {
0096: return PluginAdapter.this .getAgentIdentifier();
0097: }
0098:
0099: public ConfigFinder getConfigFinder() {
0100: return PluginAdapter.this .getConfigFinder();
0101: }
0102:
0103: public ServiceBroker getServiceBroker() {
0104: return bs.getServiceBroker();
0105: }
0106:
0107: public void requestStop() {
0108: bs.requestStop();
0109: }
0110: };
0111: }
0112:
0113: protected final PluginBindingSite getBindingSite() {
0114: return bindingSite;
0115: }
0116:
0117: //
0118: // extra services
0119: //
0120:
0121: private MessageAddress agentId = null;
0122:
0123: public final void setAgentIdentificationService(
0124: AgentIdentificationService ais) {
0125: if (ais == null) {
0126: // Revocation
0127: } else {
0128: this .agentId = ais.getMessageAddress();
0129: }
0130: }
0131:
0132: private LDMService ldmService = null;
0133:
0134: public final void setLDMService(LDMService s) {
0135: ldmService = s;
0136: }
0137:
0138: protected final LDMService getLDMService() {
0139: return ldmService;
0140: }
0141:
0142: // alarm service
0143: private AlarmService alarmService = null;
0144:
0145: public final void setAlarmService(AlarmService s) {
0146: alarmService = s;
0147: }
0148:
0149: protected final AlarmService getAlarmService() {
0150: return alarmService;
0151: }
0152:
0153: // demo control service
0154: private DemoControlService demoControlService = null;
0155:
0156: public final void setDemoControlService(DemoControlService dcs) {
0157: demoControlService = dcs;
0158: }
0159:
0160: protected final DemoControlService getDemoControlService() {
0161: return demoControlService;
0162: }
0163:
0164: private SchedulerService schedulerService = null;
0165:
0166: public final void setSchedulerService(SchedulerService ss) {
0167: schedulerService = ss;
0168: }
0169:
0170: protected final SchedulerService getSchedulerService() {
0171: return schedulerService;
0172: }
0173:
0174: //UID service
0175: private UIDService theUIDService = null;
0176:
0177: public void setUIDService(UIDService us) {
0178: theUIDService = us;
0179: }
0180:
0181: public final UIDService getUIDService() {
0182: return theUIDService;
0183: }
0184:
0185: //Domain service (factory service piece of old LDM)
0186: private DomainService theDomainService = null;
0187:
0188: public void setDomainService(DomainService ds) {
0189: theDomainService = ds;
0190: }
0191:
0192: public final DomainService getDomainService() {
0193: return theDomainService;
0194: }
0195:
0196: //PrototypeRegistryService (prototype/property piece of old LDM)
0197: private PrototypeRegistryService thePrototypeRegistryService = null;
0198:
0199: public void setPrototypeRegistryService(PrototypeRegistryService prs) {
0200: thePrototypeRegistryService = prs;
0201: }
0202:
0203: public final PrototypeRegistryService getPrototypeRegistryService() {
0204: return thePrototypeRegistryService;
0205: }
0206:
0207: //
0208: // Implement (some of) BlackboardClient
0209: //
0210: protected String blackboardClientName = null;
0211:
0212: public String getBlackboardClientName() {
0213: if (blackboardClientName == null) {
0214: StringBuffer buf = new StringBuffer();
0215: buf.append(getClass().getName());
0216: if (parameters != null) {
0217: buf.append("[");
0218: String sep = "";
0219: for (Enumeration params = parameters.elements(); params
0220: .hasMoreElements();) {
0221: buf.append(sep);
0222: buf.append(params.nextElement().toString());
0223: sep = ",";
0224: }
0225: buf.append("]");
0226: }
0227: blackboardClientName = buf.substring(0);
0228: }
0229: return blackboardClientName;
0230: }
0231:
0232: public String toString() {
0233: return getBlackboardClientName();
0234: }
0235:
0236: //
0237: // implement ParameterizedPlugin
0238: //
0239:
0240: /**
0241: * Support "interval parameters" which are long values that can be
0242: * expressed with time period units (e.g. seconds)
0243: **/
0244: private static class Interval {
0245: String name;
0246: long factor;
0247:
0248: public Interval(String name, long factor) {
0249: this .name = name;
0250: this .factor = factor;
0251: }
0252: }
0253:
0254: /**
0255: * The known unit names
0256: **/
0257: private static Interval[] intervals = {
0258: new Interval("seconds", 1000L),
0259: new Interval("minutes", 1000L * 60L),
0260: new Interval("hours", 1000L * 60L * 60L),
0261: new Interval("days", 1000L * 60L * 60L * 24L),
0262: new Interval("weeks", 1000L * 60L * 60L * 24L * 7L), };
0263:
0264: /**
0265: * Make this utility trivially accessible to plugins
0266: **/
0267: public long parseIntervalParameter(int paramIndex) {
0268: return parseInterval((String) getParameters().get(paramIndex));
0269: }
0270:
0271: public long parseInterval(String param) {
0272: param = param.trim();
0273: int spacePos = param.indexOf(' ');
0274: long factor = 1L;
0275: if (spacePos >= 0) {
0276: String units = param.substring(spacePos + 1).toLowerCase();
0277: param = param.substring(0, spacePos);
0278: for (int i = 0; i < intervals.length; i++) {
0279: if (intervals[i].name.startsWith(units)) {
0280: factor = intervals[i].factor;
0281: break;
0282: }
0283: }
0284: }
0285: return Long.parseLong(param) * factor;
0286: }
0287:
0288: // Many plugins expect a non-null value
0289: private Vector parameters = new Vector(0);
0290:
0291: public void setParameter(Object param) {
0292: if (param != null) {
0293: if (param instanceof List) {
0294: parameters = new Vector((List) param);
0295: } else {
0296: System.err.println("Warning: " + this
0297: + " initialized with non-vector parameter "
0298: + param);
0299: }
0300: }
0301: }
0302:
0303: /** get any Plugin parameters passed by the plugin instantiator.
0304: * If they haven't been set, will return null.
0305: * Should be set between plugin construction and initialization.
0306: **/
0307: public Vector getParameters() {
0308: return parameters;
0309: }
0310:
0311: //
0312: // StateModel extensions
0313: //
0314:
0315: /** Component Model <em>AND</em> GenericStateModel initialization **/
0316: public void initialize() {
0317: super .initialize(); // uninitialized->unloaded (defined in GSMAdapter)
0318: }
0319:
0320: public void load() throws StateModelException {
0321: if (getBlackboardService() == null)
0322: System.err
0323: .println("Warning: Could not get Blackboard service "
0324: + this );
0325: super .load();
0326: load(null);
0327: }
0328:
0329: /** Load the plugin. No longer pays any attention to the passed object,
0330: * as it will now always be null.
0331: **/
0332: public void load(Object object) {
0333: setThreadingChoice(getThreadingChoice()); // choose the threading model
0334: theLDM = getLDMService().getLDM();
0335: theLDMF = (PlanningFactory) getDomainService().getFactory(
0336: "planning");
0337:
0338: if (this instanceof PrototypeProvider) {
0339: getPrototypeRegistryService().addPrototypeProvider(
0340: (PrototypeProvider) this );
0341: }
0342: if (this instanceof PropertyProvider) {
0343: getPrototypeRegistryService().addPropertyProvider(
0344: (PropertyProvider) this );
0345: }
0346: if (this instanceof LatePropertyProvider) {
0347: getPrototypeRegistryService().addLatePropertyProvider(
0348: (LatePropertyProvider) this );
0349: }
0350:
0351: //ServiceBroker sb = getBindingSite().getServiceBroker();
0352:
0353: // fire up the threading model
0354: setThreadingModel(createThreadingModel());
0355: }
0356:
0357: /** */
0358: public void start() throws StateModelException {
0359: super .start();
0360: startThreadingModel();
0361: }
0362:
0363: public void suspend() throws StateModelException {
0364: super .suspend();
0365: threadingModel.suspend();
0366: }
0367:
0368: public void resume() throws StateModelException {
0369: super .resume();
0370: threadingModel.resume();
0371: }
0372:
0373: //
0374: // Customization of PluginAdapter
0375: //
0376:
0377: public int getSubscriptionCount() {
0378: return getBlackboardService().getSubscriptionCount();
0379: }
0380:
0381: public int getSubscriptionSize() {
0382: return getBlackboardService().getSubscriptionSize();
0383: }
0384:
0385: public int getPublishAddedCount() {
0386: return getBlackboardService().getPublishAddedCount();
0387: }
0388:
0389: public int getPublishChangedCount() {
0390: return getBlackboardService().getPublishChangedCount();
0391: }
0392:
0393: public int getPublishRemovedCount() {
0394: return getBlackboardService().getPublishRemovedCount();
0395: }
0396:
0397: //
0398: // Ivars and accessor methods
0399: //
0400:
0401: //Blackboard service
0402: private BlackboardService theBlackboard = null;
0403:
0404: public void setBlackboardService(BlackboardService s) {
0405: theBlackboard = s;
0406: }
0407:
0408: /** Safely return our BlackboardService
0409: * Plugin.load() must have completed in order
0410: * for the value to be defined.
0411: **/
0412: public final BlackboardService getBlackboardService() {
0413: return theBlackboard;
0414: }
0415:
0416: /** let subclasses get ahold of the cluster without having to catch it at
0417: * load time. May throw a runtime exception if the plugin hasn't been
0418: * loaded yet.
0419: * @deprecated This method no longer allows direct access to the Cluster (Agent): instead
0420: * it will always return null.
0421: **/
0422: protected final ClusterServesPlugin getCluster() {
0423: return dummyCluster;
0424: }
0425:
0426: private ClusterServesPlugin dummyCluster = new ClusterServesPlugin() {
0427: // real ones
0428: public ConfigFinder getConfigFinder() {
0429: return PluginAdapter.this .getConfigFinder();
0430: }
0431:
0432: public MessageAddress getMessageAddress() {
0433: return PluginAdapter.this .getMessageAddress();
0434: }
0435:
0436: public UIDServer getUIDServer() {
0437: return PluginAdapter.this .getUIDServer();
0438: }
0439:
0440: public LDMServesPlugin getLDM() {
0441: return PluginAdapter.this .getLDM();
0442: }
0443:
0444: // DemoControl service
0445: public void setTime(long time) {
0446: getDemoControlService().setSocietyTime(time);
0447: }
0448:
0449: public void setTime(long time, boolean foo) {
0450: getDemoControlService().setSocietyTime(time, foo);
0451: }
0452:
0453: public void setTimeRate(double rate) {
0454: getDemoControlService().setSocietyTimeRate(rate);
0455: }
0456:
0457: public void advanceTime(long period) {
0458: getDemoControlService().advanceSocietyTime(period);
0459: }
0460:
0461: public void advanceTime(long period, boolean foo) {
0462: getDemoControlService().advanceSocietyTime(period, foo);
0463: }
0464:
0465: public void advanceTime(long period, double rate) {
0466: getDemoControlService().advanceSocietyTime(period, rate);
0467: }
0468:
0469: public void advanceTime(ExecutionTimer.Change[] changes) {
0470: getDemoControlService().advanceSocietyTime(changes);
0471: }
0472:
0473: public double getExecutionRate() {
0474: return getDemoControlService().getExecutionRate();
0475: }
0476:
0477: // alarm service
0478: public long currentTimeMillis() {
0479: return getAlarmService().currentTimeMillis();
0480: }
0481:
0482: public void addAlarm(Alarm alarm) {
0483: getAlarmService().addAlarm(alarm);
0484: }
0485:
0486: public void addRealTimeAlarm(Alarm a) {
0487: getAlarmService().addRealTimeAlarm(a);
0488: }
0489:
0490: // ??
0491: public java.sql.Connection getDatabaseConnection(Object locker) {
0492: throw new RuntimeException("Should not be called");
0493: }
0494:
0495: public void releaseDatabaseConnection(Object locker) {
0496: throw new RuntimeException("Should not be called");
0497: }
0498: };
0499:
0500: protected ConfigFinder getConfigFinder() {
0501: return ConfigFinder.getInstance();
0502: }
0503:
0504: //
0505: // aliases for Transaction handling
0506: //
0507:
0508: protected final void openTransaction() {
0509: getBlackboardService().openTransaction();
0510: }
0511:
0512: protected final boolean tryOpenTransaction() {
0513: return getBlackboardService().tryOpenTransaction();
0514: }
0515:
0516: protected final void closeTransaction() throws SubscriberException {
0517: getBlackboardService().closeTransaction();
0518: }
0519:
0520: protected final void closeTransactionDontReset()
0521: throws SubscriberException {
0522: getBlackboardService().closeTransactionDontReset();
0523: }
0524:
0525: protected final void closeTransaction(boolean resetp)
0526: throws SubscriberException {
0527: getBlackboardService().closeTransaction(resetp);
0528: }
0529:
0530: //
0531: // aliases for kicking watchers
0532: //
0533:
0534: /** storage for wasAwakened. Set/reset by run() **/
0535: private boolean explicitlyAwakened = false;
0536:
0537: /** true IFF were we awakened explicitly (i.e. we were asked to run
0538: * even if no subscription activity has happened).
0539: * The value is valid only while running in the main plugin thread.
0540: */
0541: protected boolean wasAwakened() {
0542: return explicitlyAwakened;
0543: }
0544:
0545: /** For adapter use only **/
0546: public final void setAwakened(boolean value) {
0547: explicitlyAwakened = value;
0548: }
0549:
0550: /**
0551: * Hook which allows a plugin thread to request that the
0552: * primary plugin thread (the execute() method) be called.
0553: * Generally used when you want the plugin to be stimulated
0554: * by some non-internal state change ( e.g. when a timer goes off,
0555: * database activity, offline server activity, etc.)
0556: *
0557: * For plugin use only; No longer called by the infrastructure.
0558: **/
0559: public final void wake() {
0560: getBlackboardService().signalClientActivity();
0561: }
0562:
0563: /** Convenience method to specify given time to stimulate plugin.
0564: * (based on COUGAAR scenario time).
0565: * Note that this facility is not appropriate to use for
0566: * load-balancing purposes, as scenario time is discontinuous
0567: * and may even stop.
0568: * @param wakeTime actual scenario time to wake in milliseconds.
0569: **/
0570: public Alarm wakeAt(long wakeTime) {
0571: long cur = getAlarmService().currentTimeMillis() + WAKE_LATENCY;
0572: if (wakeTime < cur) {
0573: System.err.println("Warning: wakeAt("
0574: + (new Date(wakeTime)) + ") is less than "
0575: + WAKE_LATENCY + "ms in the future!");
0576: Thread.dumpStack();
0577: wakeTime = cur;
0578: }
0579:
0580: PluginAlarm pa = new PluginAlarm(wakeTime);
0581: getAlarmService().addAlarm(pa);
0582: return pa;
0583: }
0584:
0585: /** Convenience method to specify period of time to wait before
0586: * stimulating plugin (based on COUGAAR scenario time).
0587: * Note that this facility is not appropriate to use for
0588: * load-balancing purposes, as scenario time is discontinuous
0589: * and may even stop.
0590: * @param delayTime (Scenario) milliseconds to wait before waking.
0591: **/
0592: public Alarm wakeAfter(long delayTime) {
0593: if (delayTime < WAKE_LATENCY) {
0594: System.err.println("Warning: wakeAfter(" + delayTime
0595: + "ms) is less than " + WAKE_LATENCY
0596: + "ms in the future!");
0597: Thread.dumpStack();
0598: delayTime = WAKE_LATENCY;
0599: }
0600:
0601: long absTime = getAlarmService().currentTimeMillis()
0602: + delayTime;
0603: PluginAlarm pa = new PluginAlarm(absTime);
0604: getAlarmService().addAlarm(pa);
0605: return pa;
0606: }
0607:
0608: /** like wakeAt() except always in real (wallclock) time.
0609: **/
0610: public Alarm wakeAtRealTime(long wakeTime) {
0611: long cur = System.currentTimeMillis() + WAKE_LATENCY;
0612: if (wakeTime < cur) {
0613: System.err.println("Warning: wakeAtRealTime("
0614: + (new Date(wakeTime)) + ") is less than "
0615: + WAKE_LATENCY + "ms in the future!");
0616: Thread.dumpStack();
0617: wakeTime = cur;
0618: }
0619:
0620: PluginAlarm pa = new PluginAlarm(wakeTime);
0621: getAlarmService().addRealTimeAlarm(pa);
0622: return pa;
0623: }
0624:
0625: /** like wakeAfter() except always in real (wallclock) time.
0626: **/
0627: public Alarm wakeAfterRealTime(long delayTime) {
0628: if (delayTime < WAKE_LATENCY) {
0629: System.err.println("Warning: wakeAfterRealTime("
0630: + delayTime + "ms) is less than " + WAKE_LATENCY
0631: + "ms in the future!");
0632: Thread.dumpStack();
0633: delayTime = WAKE_LATENCY;
0634: }
0635:
0636: long absTime = System.currentTimeMillis() + delayTime;
0637: PluginAlarm pa = new PluginAlarm(absTime);
0638: getAlarmService().addRealTimeAlarm(pa);
0639: return pa;
0640: }
0641:
0642: /** What is the current Scenario time?
0643: * Note that this facility is not appropriate to use for
0644: * load-balancing purposes, as scenario time is discontinuous
0645: * and may even stop.
0646: **/
0647: public long currentTimeMillis() {
0648: return getAlarmService().currentTimeMillis();
0649: }
0650:
0651: /** what is the current (COUGAAR) time as a Date object?
0652: * Note: currentTimeMillis() is preferred, as it gives
0653: * more control over timezone, calendar, etc.
0654: * Note that this facility is not appropriate to use for
0655: * load-balancing purposes, as scenario time is discontinuous
0656: * and may even stop.
0657: **/
0658: public Date getDate() {
0659: return new Date(currentTimeMillis());
0660: }
0661:
0662: //
0663: // aliases for subscriptions
0664: //
0665:
0666: /** Request a subscription to all objects for which
0667: * isMember.execute(object) is true. The returned Collection
0668: * is a transactionally-safe set of these objects which is
0669: * guaranteed not to change out from under you during run()
0670: * execution.
0671: *
0672: * subscribe() may be called any time after
0673: * load() completes.
0674: *
0675: * NOTE: we'll probably want a "new things" sort of collection
0676: * for expanders.
0677: * Alias for getBlackboardService().subscribe(UnaryPredicate);
0678: **/
0679: protected final Subscription subscribe(UnaryPredicate isMember) {
0680: return getBlackboardService().subscribe(isMember);
0681: }
0682:
0683: /** like subscribe(UnaryPredicate), but allows specification of
0684: * some other type of Collection object as the internal representation
0685: * of the collection.
0686: * Alias for getBlackboardService().subscribe(UnaryPredicate, Collection);
0687: **/
0688: protected final Subscription subscribe(UnaryPredicate isMember,
0689: Collection realCollection) {
0690: return getBlackboardService().subscribe(isMember,
0691: realCollection);
0692: }
0693:
0694: /**
0695: * Alias for getBlackboardService().subscribe(UnaryPredicate, boolean);
0696: **/
0697: protected final Subscription subscribe(UnaryPredicate isMember,
0698: boolean isIncremental) {
0699: return getBlackboardService()
0700: .subscribe(isMember, isIncremental);
0701: }
0702:
0703: /**
0704: * Alias for <code>getBlackboardService().subscribe(UnaryPredicate, Collection, boolean);</code>
0705: * @param isMember a predicate to execute to ascertain
0706: * membership in the collection of the subscription.
0707: * @param realCollection a container to hold the contents of the subscription.
0708: * @param isIncremental should be true if an incremental subscription is desired.
0709: * An incremental subscription provides access to the incremental changes to the subscription.
0710: * @return the Subsciption.
0711: * @see org.cougaar.core.blackboard.Subscriber#subscribe
0712: * @see org.cougaar.core.blackboard.Subscription
0713: **/
0714: protected final Subscription subscribe(UnaryPredicate isMember,
0715: Collection realCollection, boolean isIncremental) {
0716: return getBlackboardService().subscribe(isMember,
0717: realCollection, isIncremental);
0718: }
0719:
0720: /** Issue a query against the logplan. Similar in function to
0721: * opening a new subscription, getting the results and immediately
0722: * closing the subscription, but can be implemented much more efficiently.
0723: * Note: the initial implementation actually does exactly this.
0724: **/
0725: protected final Collection query(UnaryPredicate isMember) {
0726: return getBlackboardService().query(isMember);
0727: }
0728:
0729: /**
0730: * Cancels the given Subscription which must have been returned by a
0731: * previous invocation of subscribe(). Alias for
0732: * <code> getBlackboardService().unsubscribe(Subscription)</code>.
0733: * @param subscription the subscription to cancel
0734: * @see org.cougaar.core.blackboard.Subscriber#unsubscribe
0735: **/
0736: protected final void unsubscribe(Subscription subscription) {
0737: getBlackboardService().unsubscribe(subscription);
0738: }
0739:
0740: //
0741: // LDM access
0742: //
0743:
0744: protected final LDMServesPlugin getLDM() {
0745: return theLDM;
0746: }
0747:
0748: protected final PlanningFactory getFactory() {
0749: return theLDMF;
0750: }
0751:
0752: protected final Factory getFactory(String s) {
0753: return getDomainService().getFactory(s);
0754: }
0755:
0756: //
0757: // agent
0758: //
0759:
0760: protected final MessageAddress getAgentIdentifier() {
0761: return agentId;
0762: }
0763:
0764: protected final MessageAddress getMessageAddress() {
0765: return getAgentIdentifier();
0766: }
0767:
0768: protected final UIDServer getUIDServer() {
0769: return getUIDService();
0770: }
0771:
0772: //
0773: // Blackboard changes publishing
0774: //
0775:
0776: protected final void publishAdd(Object o) {
0777: getBlackboardService().publishAdd(o);
0778: }
0779:
0780: protected final void publishRemove(Object o) {
0781: getBlackboardService().publishRemove(o);
0782: }
0783:
0784: protected final void publishChange(Object o) {
0785: getBlackboardService().publishChange(o, null);
0786: }
0787:
0788: /** mark an element of the Plan as changed.
0789: * Behavior is not defined if the object is not a member of the plan.
0790: * There is no need to call this if the object was added or removed,
0791: * only if the contents of the object itself has been changed.
0792: * The changes parameter describes a set of changes made to the
0793: * object beyond those tracked automatically by the object class
0794: * (see the object class documentation for a description of which
0795: * types of changes are tracked). Any additional changes are
0796: * merged in <em>after</em> automatically collected reports.
0797: * @param changes a set of ChangeReport instances or null.
0798: **/
0799: protected final void publishChange(Object o, Collection changes) {
0800: getBlackboardService().publishChange(o, changes);
0801: }
0802:
0803: private PluginDelegate delegate = null;
0804:
0805: /** @return an object that exposes the protected plugin methods
0806: * as publics.
0807: **/
0808: protected final PluginDelegate getDelegate() {
0809: if (delegate == null)
0810: delegate = createDelegate();
0811: return delegate;
0812: }
0813:
0814: protected PluginDelegate createDelegate() {
0815: return new Delegate();
0816: }
0817:
0818: //
0819: // implement PluginDelegate
0820: //
0821: protected class Delegate implements PluginDelegate {
0822: public ServiceBroker getServiceBroker() {
0823: return PluginAdapter.this .getBindingSite()
0824: .getServiceBroker();
0825: }
0826:
0827: public BlackboardService getBlackboardService() {
0828: return theBlackboard;
0829: }
0830:
0831: public BlackboardService getSubscriber() {
0832: return theBlackboard;
0833: }
0834:
0835: public ClusterServesPlugin getCluster() {
0836: return PluginAdapter.this .getCluster();
0837: }
0838:
0839: public LDMServesPlugin getLDM() {
0840: return getLDMService().getLDM();
0841: }
0842:
0843: public PlanningFactory getFactory() {
0844: return PluginAdapter.this .getFactory();
0845: }
0846:
0847: public Factory getFactory(String s) {
0848: return PluginAdapter.this .getFactory(s);
0849: }
0850:
0851: public MessageAddress getMessageAddress() {
0852: return PluginAdapter.this .getAgentIdentifier();
0853: }
0854:
0855: public void openTransaction() {
0856: getBlackboardService().openTransaction();
0857: }
0858:
0859: public boolean tryOpenTransaction() {
0860: return getBlackboardService().tryOpenTransaction();
0861: }
0862:
0863: public void closeTransaction() throws SubscriberException {
0864: getBlackboardService().closeTransaction();
0865: }
0866:
0867: public void closeTransactionDontReset()
0868: throws SubscriberException {
0869: getBlackboardService().closeTransactionDontReset();
0870: }
0871:
0872: public void closeTransaction(boolean resetp)
0873: throws SubscriberException {
0874: getBlackboardService().closeTransaction(resetp);
0875: }
0876:
0877: public boolean wasAwakened() {
0878: return PluginAdapter.this .wasAwakened();
0879: }
0880:
0881: public void wake() {
0882: PluginAdapter.this .wake();
0883: }
0884:
0885: public Alarm wakeAt(long n) {
0886: return PluginAdapter.this .wakeAt(n);
0887: }
0888:
0889: public Alarm wakeAfter(long n) {
0890: return PluginAdapter.this .wakeAfter(n);
0891: }
0892:
0893: public Alarm wakeAtRealTime(long n) {
0894: return PluginAdapter.this .wakeAtRealTime(n);
0895: }
0896:
0897: public Alarm wakeAfterRealTime(long n) {
0898: return PluginAdapter.this .wakeAfterRealTime(n);
0899: }
0900:
0901: public long currentTimeMillis() {
0902: return getAlarmService().currentTimeMillis();
0903: }
0904:
0905: public Date getDate() {
0906: return new Date(currentTimeMillis());
0907: }
0908:
0909: public Subscription subscribe(UnaryPredicate isMember) {
0910: return getBlackboardService().subscribe(isMember);
0911: }
0912:
0913: public Subscription subscribe(UnaryPredicate isMember,
0914: Collection realCollection) {
0915: return getBlackboardService().subscribe(isMember,
0916: realCollection);
0917: }
0918:
0919: public Subscription subscribe(UnaryPredicate isMember,
0920: boolean isIncremental) {
0921: return getBlackboardService().subscribe(isMember,
0922: isIncremental);
0923: }
0924:
0925: public Subscription subscribe(UnaryPredicate isMember,
0926: Collection realCollection, boolean isIncremental) {
0927: return getBlackboardService().subscribe(isMember,
0928: realCollection, isIncremental);
0929: }
0930:
0931: public void unsubscribe(Subscription collection) {
0932: getBlackboardService().unsubscribe(collection);
0933: }
0934:
0935: public Collection query(UnaryPredicate isMember) {
0936: return PluginAdapter.this .query(isMember);
0937: }
0938:
0939: public void publishAdd(Object o) {
0940: getBlackboardService().publishAdd(o);
0941: }
0942:
0943: public void publishRemove(Object o) {
0944: getBlackboardService().publishRemove(o);
0945: }
0946:
0947: public void publishChange(Object o) {
0948: getBlackboardService().publishChange(o, null);
0949: }
0950:
0951: public void publishChange(Object o, Collection changes) {
0952: getBlackboardService().publishChange(o, changes);
0953: }
0954:
0955: public Collection getParameters() {
0956: return parameters;
0957: }
0958:
0959: public boolean didRehydrate() {
0960: return getBlackboardService().didRehydrate();
0961: }
0962:
0963: public boolean didRehydrate(BlackboardService subscriber) {
0964: return subscriber.didRehydrate();
0965: }
0966:
0967: public boolean claim(Object o) {
0968: return PluginAdapter.this .claim(o);
0969: }
0970:
0971: public void unclaim(Object o) {
0972: PluginAdapter.this .unclaim(o);
0973: }
0974: }
0975:
0976: public boolean didRehydrate() {
0977: return getBlackboardService().didRehydrate();
0978: }
0979:
0980: public boolean didRehydrate(BlackboardService subscriber) {
0981: return subscriber.didRehydrate();
0982: }
0983:
0984: /** Attempt to stake a claim on a logplan object, essentially telling
0985: * everyone else that you and only you will be disposing, modifying, etc.
0986: * it.
0987: * Calls Claimable.tryClaim if the object is Claimable.
0988: * @return true IFF success.
0989: **/
0990: protected boolean claim(Object o) {
0991: if (o instanceof Claimable) {
0992: return ((Claimable) o).tryClaim(getBlackboardService());
0993: } else {
0994: return false;
0995: }
0996: }
0997:
0998: /** Release an existing claim on a logplan object. This is likely to
0999: * thow an exception if the object had not previously been (successfully)
1000: * claimed by this plugin.
1001: **/
1002: protected void unclaim(Object o) {
1003: ((Claimable) o).resetClaim(getBlackboardService());
1004: }
1005:
1006: //
1007: // threading model
1008: //
1009:
1010: /** called from PluginBinder **/
1011: public void plugin_prerun() {
1012: try {
1013: //start(); // just in case.. ACK! NO!
1014: BlackboardClient.current.set(this );
1015: prerun();
1016: } finally {
1017: BlackboardClient.current.set(null);
1018: }
1019: }
1020:
1021: /** override to define prerun behavior **/
1022: protected void prerun() {
1023: }
1024:
1025: /** called from PluginBinder **/
1026: public void plugin_cycle() {
1027: try {
1028: BlackboardClient.current.set(this );
1029: cycle();
1030: } finally {
1031: BlackboardClient.current.set(null);
1032: }
1033: }
1034:
1035: /** override to define cycle behavior **/
1036: protected void cycle() {
1037: }
1038:
1039: //
1040: // compatability methods
1041: //
1042:
1043: /** alias for getBlackboardService **/
1044: protected BlackboardService getSubscriber() {
1045: return getBlackboardService();
1046: }
1047:
1048: public class PluginAlarm implements Alarm {
1049: private long expiresAt;
1050: private boolean expired = false;
1051:
1052: public PluginAlarm(long expirationTime) {
1053: expiresAt = expirationTime;
1054: }
1055:
1056: public long getExpirationTime() {
1057: return expiresAt;
1058: }
1059:
1060: public synchronized void expire() {
1061: if (!expired) {
1062: expired = true;
1063: getBlackboardService().signalClientActivity();
1064: }
1065: }
1066:
1067: public boolean hasExpired() {
1068: return expired;
1069: }
1070:
1071: public synchronized boolean cancel() {
1072: boolean was = expired;
1073: expired = true;
1074: return was;
1075: }
1076:
1077: public String toString() {
1078: return "<PluginAlarm " + expiresAt
1079: + (expired ? "(Expired) " : " ") + "for "
1080: + PluginAdapter.this .toString() + ">";
1081: }
1082: }
1083:
1084: //
1085: // threading model support
1086: //
1087:
1088: private Threading threadingModel = null;
1089:
1090: protected final void setThreadingModel(Threading t) {
1091: threadingModel = t;
1092: }
1093:
1094: protected final Threading getThreadingModel() {
1095: return threadingModel;
1096: }
1097:
1098: public final static int UNSPECIFIED_THREAD = -1;
1099: public final static int NO_THREAD = 0;
1100: public final static int SHARED_THREAD = 1;
1101: public final static int SINGLE_THREAD = 2;
1102: public final static int ONESHOT_THREAD = 3;
1103:
1104: private int threadingChoice = UNSPECIFIED_THREAD;
1105:
1106: /** Set the current choice of threading model. Will have no effect if
1107: * the threading model has already been acted on.
1108: **/
1109: protected final void setThreadingChoice(int m) {
1110: if (threadingModel != null)
1111: throw new IllegalArgumentException(
1112: "Too late to select threading model for " + this );
1113: threadingChoice = m;
1114: }
1115:
1116: /** Set the current choice of threading model. Will have no effect if
1117: * the threading model has already been acted on.
1118: **/
1119: protected final void chooseThreadingModel(int m) {
1120: setThreadingChoice(m);
1121: }
1122:
1123: /** @return the current choice of threading model. **/
1124: protected final int getThreadingChoice() {
1125: return threadingChoice;
1126: }
1127:
1128: /** create a Threading model object as specified by the plugin.
1129: * The default implementation creates a Threading object
1130: * based on the value of threadingChoice.
1131: * The default choice is to use a SharedThreading model, which
1132: * shares thread of execution with others of the same sort in
1133: * the agent.
1134: * Most plugins can ignore this altogether. Most that
1135: * want to select different behavior should
1136: * call chooseThreadingModel() in their constructer.
1137: * Plugins which implement their own threading model
1138: * will need to override createThreadingModel.
1139: * createThreadingModel is called late in PluginBinder.load().
1140: * if an extending plugin class wishes to examine or alter
1141: * the threading model object, it will be available only when
1142: * PluginBinder.load() returns, which is usually called by
1143: * the extending plugin classes overriding load() method.
1144: * The constructed Threading object is initialized by
1145: * PluginBinder.start().
1146: **/
1147: protected Threading createThreadingModel() {
1148: Threading t;
1149: switch (getThreadingChoice()) {
1150: case NO_THREAD:
1151: t = new NoThreading();
1152: break;
1153: case SHARED_THREAD:
1154: t = new SharedThreading();
1155: break;
1156: case SINGLE_THREAD:
1157: t = new SingleThreading();
1158: break;
1159: case ONESHOT_THREAD:
1160: t = new OneShotThreading();
1161: break;
1162: default:
1163: throw new RuntimeException("Invalid Threading model "
1164: + getThreadingChoice());
1165: }
1166: return t;
1167: }
1168:
1169: public void startThreadingModel() {
1170: try {
1171: threadingModel.initialize();
1172: threadingModel.load();
1173: threadingModel.start();
1174: } catch (RuntimeException e) {
1175: System.err
1176: .println("Caught exception during threadingModel initialization: "
1177: + e);
1178: e.printStackTrace();
1179: }
1180: }
1181:
1182: protected abstract class Threading implements GenericStateModel {
1183: public void initialize() {
1184: }
1185:
1186: /** the argument passed to load is a ClusterServesPlugin **/
1187: public void load() {
1188: }
1189:
1190: public void start() {
1191: }
1192:
1193: public void suspend() {
1194: }
1195:
1196: public void resume() {
1197: }
1198:
1199: public void stop() {
1200: }
1201:
1202: public void halt() {
1203: }
1204:
1205: public void unload() {
1206: }
1207:
1208: public int getModelState() {
1209: return UNINITIALIZED;
1210: }
1211:
1212: public String toString() {
1213: return getAgentIdentifier() + "/" + PluginAdapter.this ;
1214: }
1215: }
1216:
1217: /** up to the class to implement what it needs **/
1218: protected class NoThreading extends Threading {
1219: }
1220:
1221: /** prerun only: cycle will never be called. **/
1222: protected class OneShotThreading extends Threading {
1223: public OneShotThreading() {
1224: }
1225:
1226: public void start() {
1227: plugin_prerun();
1228: }
1229: }
1230:
1231: /**
1232: * Shares a Thread with other SharedThreading plugins in the same agent.
1233: * <p>
1234: * There are two callbacks:<ul>
1235: * <li>the subscription watcher, to track blackboard activity</li>
1236: * <li>the scheduler trigger, to request plugin_cycle()</li>
1237: * </ul><br>
1238: * The order is:<ol>
1239: * <li>the blackboard calls "subscriptionWatcher.signalNotify(..)"</li>
1240: * <li>the subscription watcher calls "schedTrigger.trigger()"</li>
1241: * <li>the scheduler calls "this.trigger()"</li>
1242: * <li>"this.trigger()" calls "plugin_cycle()"</li>
1243: * </li>.
1244: */
1245: protected class SharedThreading extends Threading {
1246:
1247: // callback for subscription activity
1248: private SubscriptionWatcher sw = null;
1249: private TriggerModel tm;
1250:
1251: private boolean didPrerun = false;
1252:
1253: public void load() {
1254: sw = new ThinWatcher();
1255: Trigger piTrig = new PluginTrigger();
1256: tm = new SyncTriggerModelImpl(getSchedulerService(), piTrig);
1257: getBlackboardService().registerInterest(sw);
1258: }
1259:
1260: public void start() {
1261: if (!(didPrerun)) {
1262: didPrerun = true;
1263: plugin_prerun();
1264: }
1265: tm.start();
1266: }
1267:
1268: public void suspend() {
1269: tm.suspend();
1270: }
1271:
1272: public void resume() {
1273: tm.resume();
1274: }
1275:
1276: public void stop() {
1277: tm.stop();
1278: }
1279:
1280: public void unload() {
1281: tm.unload();
1282: getBlackboardService().unregisterInterest(sw);
1283: sw = null;
1284: }
1285:
1286: // implement Trigger
1287:
1288: private class PluginTrigger implements Trigger {
1289: // no need to "sync" when using "SyncTriggerModel"
1290: public void trigger() {
1291: // get wake() right
1292: setAwakened(sw.clearSignal());
1293: plugin_cycle();
1294: }
1295: }
1296:
1297: private class ThinWatcher extends SubscriptionWatcher {
1298: public void signalNotify(int event) {
1299: super .signalNotify(event);
1300: tm.trigger();
1301: }
1302:
1303: public String toString() {
1304: return "ThinWatcher(" + PluginAdapter.this .toString()
1305: + ")";
1306: }
1307: }
1308:
1309: public String toString() {
1310: return this .getClass().getName() + "("
1311: + PluginAdapter.this .toString() + ")";
1312: }
1313: }
1314:
1315: /** has its own Thread **/
1316: protected class SingleThreading extends Threading implements
1317: Runnable {
1318: /** a reference to personal Thread which each Plugin runs in **/
1319: private Thread myThread = null;
1320: /** our subscription watcher **/
1321: private SubscriptionWatcher waker = null;
1322: private static final int STOPPED = 0;
1323: private static final int SUSPENDED = 1;
1324: private static final int RUNNING = 2;
1325: private int state = STOPPED;
1326: private boolean firstRun = true;
1327:
1328: public SingleThreading() {
1329: }
1330:
1331: private int priority = Thread.NORM_PRIORITY;
1332:
1333: /** plugins and subclasses may set the Thread priority to
1334: * a value lower than standard. Requests to raise the priority
1335: * are ignored as are all requests after start()
1336: * Note that the default priority is one level below the
1337: * usual java priority - that is one level below where the
1338: * infrastructure runs.
1339: **/
1340: public void setPriority(int newPriority) {
1341: if (newPriority < priority) {
1342: priority = newPriority;
1343: }
1344: }
1345:
1346: private boolean isYielding = true;
1347:
1348: /** If isYielding is true, the plugin will force a thread yield
1349: * after each call to cycle(). This is on by default since plugins
1350: * generally need reaction from infrastructure and other plugins
1351: * to progress.
1352: * This may be set at any time, even though the effect is only periodic.
1353: * Most plugins would want to (re)set this value at initialization.
1354: **/
1355: public void setIsYielding(boolean v) {
1356: isYielding = v;
1357: }
1358:
1359: public void load() {
1360: setWaker(getBlackboardService().registerInterest());
1361: }
1362:
1363: public void unload() {
1364: getBlackboardService().unregisterInterest(getWaker());
1365: }
1366:
1367: public synchronized void start() {
1368: if (state != STOPPED)
1369: throw new RuntimeException("Not stopped");
1370: state = RUNNING;
1371: firstRun = true;
1372: startThread();
1373: }
1374:
1375: public synchronized void suspend() {
1376: if (state != RUNNING)
1377: throw new RuntimeException("Not running");
1378: state = SUSPENDED;
1379: stopThread();
1380: }
1381:
1382: public synchronized void resume() {
1383: if (state != SUSPENDED)
1384: throw new RuntimeException("Not suspended");
1385: state = RUNNING;
1386: startThread();
1387: }
1388:
1389: public synchronized void stop() {
1390: if (state != SUSPENDED)
1391: throw new RuntimeException("Not suspended");
1392: state = RUNNING;
1393: startThread();
1394: suspend();
1395: }
1396:
1397: private void startThread() {
1398: myThread = new Thread(this , "Plugin/"
1399: + getAgentIdentifier() + "/" + PluginAdapter.this );
1400: myThread.setPriority(priority);
1401: myThread.start();
1402: }
1403:
1404: private void stopThread() {
1405: signalStateChange();
1406: try {
1407: myThread.join(60000);
1408: } catch (InterruptedException ie) {
1409: }
1410: myThread = null;
1411: }
1412:
1413: private void signalStateChange() {
1414: if (waker != null) {
1415: waker.signalNotify(waker.INTERNAL);
1416: }
1417: }
1418:
1419: public final void run() {
1420: if (firstRun) {
1421: plugin_prerun(); // plugin first time through
1422: firstRun = false;
1423: }
1424: while (state == RUNNING) {
1425: boolean xwakep = waker.waitForSignal();
1426: setAwakened(xwakep);
1427: plugin_cycle(); // do work
1428: if (isYielding)
1429: Thread.yield();
1430: }
1431: }
1432:
1433: public void setWaker(SubscriptionWatcher sw) {
1434: waker = sw;
1435: }
1436:
1437: public SubscriptionWatcher getWaker() {
1438: return waker;
1439: }
1440: }
1441: }
|