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.plugin;
028:
029: import java.util.Date;
030:
031: import org.cougaar.core.agent.service.alarm.Alarm;
032: import org.cougaar.core.component.ServiceBroker;
033: import org.cougaar.core.logging.LoggingServiceWithPrefix;
034: import org.cougaar.core.service.BlackboardService;
035: import org.cougaar.core.service.LoggingService;
036:
037: /**
038: * This component is a convenience base class for plugins that
039: * need to acquire services that may not be immediately available
040: * when first started.
041: * <p>
042: * Records the service classes needed and attempts acquire them
043: * on request. Also provides timer services.
044: * <p>
045: * Instead of using this class, consider using a {@link
046: * org.cougaar.core.component.ServiceAvailableListener}.
047: */
048: public abstract class ServiceUserPlugin extends ComponentPlugin {
049: private Class[] serviceClasses;
050:
051: private boolean[] serviceAcquired;
052:
053: private boolean allServicesAcquired = false;
054:
055: /**
056: * Everybody needs a logger, so we provide it here.
057: */
058: private LoggingService loggingService;
059: protected LoggingService logger;
060:
061: /**
062: * Constructor
063: * @param serviceClasses the service classes needed for this plugin
064: * to operate.
065: */
066: protected ServiceUserPlugin(Class[] serviceClasses) {
067: this .serviceClasses = serviceClasses;
068: this .serviceAcquired = new boolean[serviceClasses.length];
069: }
070:
071: /**
072: * Override to get a logger on load
073: */
074: public void load() {
075: super .load();
076: loggingService = (LoggingService) getServiceBroker()
077: .getService(this , LoggingService.class, null);
078: logger = LoggingServiceWithPrefix.add(loggingService,
079: getAgentIdentifier().toString() + ": ");
080: }
081:
082: /**
083: * Override to release a logger on load
084: */
085: public void unload() {
086: if (loggingService != null) {
087: getServiceBroker().releaseService(this ,
088: LoggingService.class, loggingService);
089: logger = null;
090: loggingService = null;
091: }
092: super .unload();
093: }
094:
095: /**
096: * Test if all services specified in the constructor are available.
097: * Sub-classes should call this method from their setupSubscriptions
098: * and execute methods until it returns true. Once this method
099: * returns true, the services should be requested and normal
100: * operation started. Once all the services are available, this
101: * method simply returns true. See <code>haveServices()</code> in
102: * {@link org.cougaar.core.adaptivity.ConditionServiceProvider#execute ConditionServiceProvider}
103: * for a typical usage pattern.
104: */
105: protected boolean acquireServices() {
106: if (!allServicesAcquired) {
107: allServicesAcquired = true; // Assume we will get them all
108: ServiceBroker sb = getServiceBroker();
109: for (int i = 0; i < serviceClasses.length; i++) {
110: if (!serviceAcquired[i]) {
111: if (sb.hasService(serviceClasses[i])) {
112: // if (logger.isDebugEnabled()) {
113: // logger.debug(serviceClasses[i].getName() + " acquired");
114: // }
115: Object o = sb.getService(this ,
116: serviceClasses[i], null);
117: if (o == null) {
118: System.out.println(serviceClasses[i]
119: .getName()
120: + " exists but is unavailable");
121: allServicesAcquired = false;
122: } else {
123: sb.releaseService(this , serviceClasses[i],
124: o);
125: serviceAcquired[i] = true;
126: }
127: } else {
128: // if (logger.isDebugEnabled()) {
129: // logger.debug(serviceClasses[i].getName() + " missing");
130: // }
131: allServicesAcquired = false;
132: }
133: }
134: }
135: if (!allServicesAcquired) {
136: resetTimer(1000L);
137: }
138: }
139: return allServicesAcquired;
140: }
141:
142: /** A timer for recurrent events. All access should be synchronized on timerLock */
143: private Alarm timer = null;
144:
145: /** Lock for accessing timer */
146: private final Object timerLock = new Object();
147:
148: /**
149: * Schedule a update wakeup after some interval of time
150: * @param delay how long to delay before the timer expires.
151: * @deprecated Use resetTimer(long) instead as a safer mechanism without so many race issues.
152: */
153: protected void startTimer(long delay) {
154: synchronized (timerLock) {
155: if (timer != null && !timer.hasExpired())
156: return; // pending event - don't restart
157:
158: // if (logger.isDebugEnabled()) logger.debug("Starting timer " + delay);
159: if (getBlackboardService() == null && logger != null
160: && logger.isWarnEnabled()) {
161: logger
162: .warn("Started service alarm before the blackboard service"
163: + " is available");
164: }
165: timer = createAlarm(System.currentTimeMillis() + delay);
166: getAlarmService().addRealTimeAlarm(timer);
167: }
168: }
169:
170: private Alarm createAlarm(long time) {
171: return new PluginAlarm(time) {
172: public BlackboardService getBlackboardService() {
173: if (blackboard == null) {
174: if (logger != null && logger.isWarnEnabled()) {
175: logger
176: .warn("Alarm to trigger at "
177: + (new Date(getExpirationTime()))
178: + " has expired,"
179: + " but the blackboard service is null. Plugin "
180: + " model state is "
181: + getModelState());
182: }
183: }
184: return blackboard;
185: }
186: };
187: }
188:
189: /**
190: * Schedule a update wakeup after some interval of time
191: * @param delay how long to delay before the timer expires.
192: */
193: protected void resetTimer(long delay) {
194: synchronized (timerLock) {
195: Alarm old = timer; // keep any old one around
196: if (old != null) {
197: old.cancel(); // cancel the old one
198: }
199: timer = createAlarm(System.currentTimeMillis() + delay);
200: getAlarmService().addRealTimeAlarm(timer);
201: }
202: }
203:
204: /**
205: * Cancel the timer.
206: */
207: protected void cancelTimer() {
208: synchronized (timerLock) {
209: if (timer == null)
210: return;
211: // if (logger.isDebugEnabled()) logger.debug("Cancelling timer");
212: timer.cancel();
213: timer = null;
214: }
215: }
216:
217: /** access the timer itself (if any) */
218: protected Alarm getTimer() {
219: synchronized (timerLock) {
220: return timer;
221: }
222: }
223:
224: /** When will (has) the timer expire */
225: protected long getTimerExpirationTime() {
226: synchronized (timerLock) {
227: if (timer != null) {
228: return timer.getExpirationTime();
229: } else {
230: return 0;
231: }
232: }
233: }
234:
235: /** Returns true IFF there is an unexpired timer.
236: */
237: protected boolean hasUnexpiredTimer() {
238: synchronized (timerLock) {
239: if (timer != null) {
240: return !timer.hasExpired();
241: } else {
242: return false;
243: }
244: }
245: }
246:
247: /**
248: * Test if the timer has expired.
249: * @return false if the timer is not running or has not yet expired
250: * else return true.
251: */
252: protected boolean timerExpired() {
253: synchronized (timerLock) {
254: return timer != null && timer.hasExpired();
255: }
256: }
257:
258: }
|