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.servicediscovery.plugin;
028:
029: import org.cougaar.core.blackboard.IncrementalSubscription;
030: import org.cougaar.core.service.LoggingService;
031: import org.cougaar.planning.ldm.asset.Asset;
032: import org.cougaar.planning.ldm.asset.NewRelationshipPG;
033: import org.cougaar.planning.ldm.plan.AspectType;
034: import org.cougaar.planning.ldm.plan.Preference;
035: import org.cougaar.planning.ldm.plan.Role;
036: import org.cougaar.planning.ldm.plan.Schedule;
037: import org.cougaar.planning.ldm.plan.ScheduleElement;
038: import org.cougaar.planning.plugin.legacy.SimplePlugin;
039: import org.cougaar.servicediscovery.SDDomain;
040: import org.cougaar.servicediscovery.SDFactory;
041: import org.cougaar.servicediscovery.description.ProviderCapabilities;
042: import org.cougaar.servicediscovery.description.ProviderCapability;
043: import org.cougaar.servicediscovery.description.ServiceContract;
044: import org.cougaar.servicediscovery.description.ServiceContractImpl;
045: import org.cougaar.servicediscovery.description.ServiceRequest;
046: import org.cougaar.servicediscovery.transaction.ProviderServiceContractRelay;
047: import org.cougaar.servicediscovery.transaction.ServiceContractRelay;
048: import org.cougaar.util.MutableTimeSpan;
049: import org.cougaar.util.TimeSpan;
050: import org.cougaar.util.UnaryPredicate;
051:
052: import java.util.ArrayList;
053: import java.util.Collection;
054: import java.util.Date;
055: import java.util.HashMap;
056: import java.util.Iterator;
057:
058: /**
059: * SDProviderPlugin generates the LineageLists for the Agent.
060: */
061: public class SDProviderPlugin extends SimplePlugin {
062: private static Integer START_TIME_KEY = new Integer(
063: AspectType.START_TIME);
064: private static Integer END_TIME_KEY = new Integer(
065: AspectType.END_TIME);
066:
067: private IncrementalSubscription mySelfOrgSubscription;
068: private IncrementalSubscription myServiceContractRelaySubscription;
069: private IncrementalSubscription myProviderCapabilitiesSubscription;
070:
071: private String myAgentName;
072:
073: protected LoggingService myLoggingService;
074:
075: protected SDFactory mySDFactory;
076:
077: private final UnaryPredicate myServiceContractRelayPred = new ServiceContractRelayPredicate();
078:
079: private final class ServiceContractRelayPredicate implements
080: UnaryPredicate {
081: public boolean execute(Object o) {
082: return ((o instanceof ProviderServiceContractRelay) && ((ServiceContractRelay) o)
083: .getProviderName().equals(myAgentName));
084: }
085: }
086:
087: private static final UnaryPredicate mySelfOrgPred = new SelfOrgPredicate();
088:
089: private static final class SelfOrgPredicate implements
090: UnaryPredicate {
091: public boolean execute(Object o) {
092: if (o instanceof Asset) {
093: Asset org = (Asset) o;
094: if (org.hasRelationshipPG()
095: && ((NewRelationshipPG) org.getRelationshipPG())
096: .getRelationshipBG() != null
097: && org.getRelationshipPG().isLocal()) {
098: return true;
099: }
100: }
101: return false;
102: }
103: }
104:
105: private final UnaryPredicate myProviderCapabilitiesPred = new ProviderCapabilitiesPredicate();
106:
107: private final class ProviderCapabilitiesPredicate implements
108: UnaryPredicate {
109: public boolean execute(Object o) {
110: if (o instanceof ProviderCapabilities) {
111: ProviderCapabilities providerCapabilities = (ProviderCapabilities) o;
112: return (providerCapabilities.getProviderName()
113: .equals(getAgentIdentifier().toString()));
114: }
115: return false;
116: }
117: }
118:
119: protected void setupSubscriptions() {
120: myLoggingService = (LoggingService) getBindingSite()
121: .getServiceBroker().getService(this ,
122: LoggingService.class, null);
123:
124: myAgentName = getBindingSite().getAgentIdentifier().toString();
125:
126: myServiceContractRelaySubscription = (IncrementalSubscription) subscribe(myServiceContractRelayPred);
127: mySelfOrgSubscription = (IncrementalSubscription) subscribe(mySelfOrgPred);
128: myProviderCapabilitiesSubscription = (IncrementalSubscription) subscribe(myProviderCapabilitiesPred);
129:
130: mySDFactory = (SDFactory) getFactory(SDDomain.SD_NAME);
131: }
132:
133: public void execute() {
134: if (myServiceContractRelaySubscription.hasChanged()) {
135:
136: Collection addedRelays = myServiceContractRelaySubscription
137: .getAddedCollection();
138: for (Iterator adds = addedRelays.iterator(); adds.hasNext();) {
139: ProviderServiceContractRelay relay = (ProviderServiceContractRelay) adds
140: .next();
141:
142: if (myLoggingService.isDebugEnabled()) {
143: myLoggingService.debug(getAgentIdentifier()
144: + ": execute() new ServiceContractRelay - "
145: + relay);
146: }
147: handleServiceContractRelay(relay);
148: }
149:
150: Collection changedRelays = myServiceContractRelaySubscription
151: .getChangedCollection();
152: for (Iterator changes = changedRelays.iterator(); changes
153: .hasNext();) {
154: ProviderServiceContractRelay relay = (ProviderServiceContractRelay) changes
155: .next();
156:
157: if (myLoggingService.isDebugEnabled()) {
158: myLoggingService
159: .debug(getAgentIdentifier()
160: + ": execute() modified ServiceContractRelay - "
161: + relay);
162: }
163: handleServiceContractRelay(relay);
164: }
165:
166: // Not currently handling removes
167: }
168:
169: if (myProviderCapabilitiesSubscription.hasChanged()) {
170: Collection changedCapabilities = myProviderCapabilitiesSubscription
171: .getChangedCollection();
172:
173: for (Iterator changes = changedCapabilities.iterator(); changes
174: .hasNext();) {
175: ProviderCapabilities capabilities = (ProviderCapabilities) changes
176: .next();
177: handleChangedProviderCapabilities(capabilities);
178: }
179: }
180: }
181:
182: protected void handleServiceContractRelay(
183: ProviderServiceContractRelay relay) {
184: ServiceRequest serviceRequest = relay.getServiceRequest();
185: ServiceContract serviceContract = relay.getServiceContract();
186:
187: HashMap contractPreferences = copyPreferences(serviceRequest
188: .getServicePreferences());
189:
190: boolean contractChanged = false;
191: boolean contractExists = (serviceContract != null);
192:
193: // Replace start/end time preferences
194: // Construct start/end pref by making request agree with capability avail
195: // schedule
196: TimeSpan requestedTimeSpan = SDFactory
197: .getTimeSpanFromPreferences(serviceRequest
198: .getServicePreferences());
199:
200: TimeSpan contractTimeSpan = (serviceContract != null) ? SDFactory
201: .getTimeSpanFromPreferences(serviceContract
202: .getServicePreferences())
203: : null;
204:
205: if (myLoggingService.isDebugEnabled()) {
206: String contractTimeSpanString = (contractTimeSpan == null) ? ""
207: : new Date(contractTimeSpan.getStartTime()) + " "
208: + new Date(contractTimeSpan.getEndTime());
209:
210: myLoggingService.debug(getAgentIdentifier()
211: + ": handleServiceContractRelay() relay = " + relay
212: + " " + relay.getUID() + " requestedTimeSpan = "
213: + new Date(requestedTimeSpan.getStartTime()) + " "
214: + new Date(requestedTimeSpan.getEndTime())
215: + contractTimeSpanString);
216: }
217:
218: Collection modifiedContractPreferences = null;
219:
220: if (requestedTimeSpan == null) {
221: if (myLoggingService.isInfoEnabled()) {
222: myLoggingService
223: .info(getAgentIdentifier()
224: + ": handleServiceContractRelay() unable to handle service request - "
225: + relay.getServiceRequest()
226: + " - does not have start and/or end time preferences.");
227: }
228:
229: // Remove start/end preferences since provider can't meet request.
230: contractPreferences.remove(START_TIME_KEY);
231: contractPreferences.remove(END_TIME_KEY);
232: contractChanged = true;
233: } else {
234: TimeSpan verifiedContractTimeSpan = checkProviderCapability(
235: getProviderCapability(serviceRequest
236: .getServiceRole()), requestedTimeSpan);
237:
238: if (verifiedContractTimeSpan == null) {
239: if (myLoggingService.isInfoEnabled()) {
240: myLoggingService
241: .info(getAgentIdentifier()
242: + ": handleServiceContractRelay() unable to handle service request - "
243: + relay.getServiceRequest()
244: + " - does not match provider capabilities.");
245: }
246:
247: // Remove start/end preferences since provider can't meet request.
248: contractPreferences.remove(START_TIME_KEY);
249: contractPreferences.remove(END_TIME_KEY);
250: contractChanged = true;
251: } else if (contractExists) {
252: //compare with existing contract
253: if (myLoggingService.isDebugEnabled()) {
254: myLoggingService.debug(getAgentIdentifier()
255: + ": handleServiceContractRelay() - "
256: + " current time span = "
257: + new Date(contractTimeSpan.getStartTime())
258: + " to "
259: + new Date(contractTimeSpan.getEndTime())
260: + " new time span = "
261: + new Date(verifiedContractTimeSpan
262: .getStartTime())
263: + " to "
264: + new Date(verifiedContractTimeSpan
265: .getEndTime())
266: + " (current == new) = "
267: + contractTimeSpan
268: .equals(verifiedContractTimeSpan));
269: }
270:
271: if (!contractTimeSpan.equals(verifiedContractTimeSpan)) {
272: // Replace contract start end with requested start end
273: modifiedContractPreferences = mySDFactory
274: .createTimeSpanPreferences(verifiedContractTimeSpan);
275:
276: contractChanged = true;
277: }
278: } else if (!verifiedContractTimeSpan
279: .equals(requestedTimeSpan)) {
280: // Replace start/end with what provider can handle.
281: modifiedContractPreferences = mySDFactory
282: .createTimeSpanPreferences(verifiedContractTimeSpan);
283:
284: contractChanged = true;
285: }
286: }
287:
288: if (modifiedContractPreferences != null) {
289: for (Iterator iterator = modifiedContractPreferences
290: .iterator(); iterator.hasNext();) {
291: Preference preference = (Preference) iterator.next();
292: contractPreferences.put(new Integer(preference
293: .getAspectType()), preference);
294: }
295: }
296:
297: if (!contractExists) {
298: if (myLoggingService.isInfoEnabled()) {
299: myLoggingService
300: .info(getAgentIdentifier()
301: + ": added new ServiceContract on a relay from "
302: + relay.getUID() + " for the role "
303: + serviceRequest.getServiceRole());
304: }
305: serviceContract = mySDFactory.newServiceContract(
306: getSelfOrg(), serviceRequest.getServiceRole(),
307: contractPreferences.values());
308: relay.setServiceContract(serviceContract);
309: } else if (contractChanged) {
310: if (myLoggingService.isInfoEnabled()) {
311: myLoggingService.info(getAgentIdentifier()
312: + ": changed ServiceContract on a relay from "
313: + relay.getUID() + " for the role "
314: + serviceRequest.getServiceRole());
315: }
316: ((ServiceContractImpl) serviceContract)
317: .setServicePreferences(contractPreferences.values());
318: }
319:
320: if ((!contractExists) || (contractChanged)) {
321: publishChange(relay);
322: }
323:
324: }
325:
326: void handleChangedProviderCapabilities(
327: ProviderCapabilities capabilities) {
328: if (myLoggingService.isInfoEnabled()) {
329: myLoggingService.info(getAgentIdentifier()
330: + " changed ProviderCapabilities " + capabilities);
331: }
332:
333: for (Iterator iterator = capabilities.getCapabilities()
334: .iterator(); iterator.hasNext();) {
335: ProviderCapability capability = (ProviderCapability) iterator
336: .next();
337: Collection contracts = getMatchingContracts(capability);
338:
339: for (Iterator relayIterator = contracts.iterator(); relayIterator
340: .hasNext();) {
341: ProviderServiceContractRelay relay = (ProviderServiceContractRelay) relayIterator
342: .next();
343: ServiceContract contract = relay.getServiceContract();
344:
345: if (!contract.isRevoked()) {
346: boolean changeRequired = false;
347:
348: TimeSpan currentContractTimeSpan = SDFactory
349: .getTimeSpanFromPreferences(contract
350: .getServicePreferences());
351:
352: if (currentContractTimeSpan != null) {
353: TimeSpan contractTimeSpan = checkProviderCapability(
354: capability, currentContractTimeSpan);
355: if (contractTimeSpan == null) {
356: if (myLoggingService.isInfoEnabled()) {
357: myLoggingService
358: .info(getAgentIdentifier()
359: + " revoking contract "
360: + relay
361: .getServiceContract()
362: + " due to provider capability change.");
363: }
364: SDFactory.revokeServiceContract(contract);
365: changeRequired = true;
366: } else if (!(currentContractTimeSpan
367: .equals(contractTimeSpan))) {
368: if (myLoggingService.isInfoEnabled()) {
369: myLoggingService
370: .info(getAgentIdentifier()
371: + " changing contract availability to match "
372: + " provider availability: current contract time span "
373: + currentContractTimeSpan
374: .getStartTime()
375: + " - "
376: + currentContractTimeSpan
377: .getEndTime()
378: + " provider capability "
379: + contractTimeSpan
380: .getStartTime()
381: + " - "
382: + contractTimeSpan
383: .getEndTime());
384: }
385:
386: HashMap copy = copyPreferences(contract
387: .getServicePreferences());
388:
389: Collection timespanPreferences = mySDFactory
390: .createTimeSpanPreferences(contractTimeSpan);
391:
392: // Replace start/end with what provider can handle.
393: for (Iterator preferenceIterator = timespanPreferences
394: .iterator(); preferenceIterator
395: .hasNext();) {
396: Preference preference = (Preference) preferenceIterator
397: .next();
398: copy.put(new Integer(preference
399: .getAspectType()), preference);
400: }
401:
402: ServiceContract newContract = mySDFactory
403: .newServiceContract(getSelfOrg(),
404: contract.getServiceRole(),
405: copy.values());
406: relay.setServiceContract(newContract);
407: changeRequired = true;
408: }
409: }
410:
411: if (changeRequired) {
412: if (myLoggingService.isInfoEnabled()) {
413: myLoggingService.info(getAgentIdentifier()
414: + " handleChangeProviderCap "
415: + " publish change relay for "
416: + contract.getServiceRole() + " "
417: + contract);
418: }
419: publishChange(relay);
420: }
421: }
422: }
423: }
424: }
425:
426: protected Collection getMatchingContracts(
427: ProviderCapability capability) {
428: ArrayList matchingRelays = new ArrayList();
429:
430: for (Iterator contracts = myServiceContractRelaySubscription
431: .getCollection().iterator(); contracts.hasNext();) {
432: ServiceContractRelay relay = (ServiceContractRelay) contracts
433: .next();
434: ServiceContract contract = relay.getServiceContract();
435: //find the service contract relay with matching role to the service disrupted
436: if (contract.getServiceRole().equals(capability.getRole())) {
437: matchingRelays.add(relay);
438: }
439: }
440: return matchingRelays;
441: }
442:
443: protected Asset getSelfOrg() {
444: for (Iterator iterator = mySelfOrgSubscription.iterator(); iterator
445: .hasNext();) {
446: return (Asset) iterator.next();
447: }
448:
449: return null;
450: }
451:
452: protected ProviderCapability getProviderCapability(Role role) {
453: for (Iterator iterator = myProviderCapabilitiesSubscription
454: .iterator(); iterator.hasNext();) {
455: ProviderCapabilities capabilities = (ProviderCapabilities) iterator
456: .next();
457: ProviderCapability capability = capabilities
458: .getCapability(role);
459:
460: if (myLoggingService.isInfoEnabled()) {
461: myLoggingService.info(getAgentIdentifier()
462: + " getCapability returned " + capability
463: + " for " + role);
464: }
465:
466: if (capability != null) {
467: return capability;
468: }
469:
470: }
471:
472: return null;
473: }
474:
475: protected TimeSpan checkProviderCapability(
476: ProviderCapability capability, TimeSpan requestedTimeSpan) {
477: // Deliberately set to invalid values so can catch case where provider
478: // doesn't handle thee specified role
479: long earliest = TimeSpan.MAX_VALUE;
480: long latest = TimeSpan.MIN_VALUE;
481:
482: if (capability != null) {
483: Schedule currentAvailability = capability
484: .getAvailableSchedule();
485:
486: Collection overlaps = currentAvailability
487: .getOverlappingScheduleElements(requestedTimeSpan
488: .getStartTime(), requestedTimeSpan
489: .getEndTime());
490:
491: if (overlaps.size() != 0) {
492: for (Iterator overlap = overlaps.iterator(); overlap
493: .hasNext();) {
494: // Take info from first overlan. We don't yet have the ability to
495: // include a schedule of timespans.
496: ScheduleElement scheduleElement = (ScheduleElement) overlap
497: .next();
498: earliest = Math.max(scheduleElement.getStartTime(),
499: requestedTimeSpan.getStartTime());
500: latest = Math.min(scheduleElement.getEndTime(),
501: requestedTimeSpan.getEndTime());
502: break;
503: }
504: } else {
505: if (myLoggingService.isInfoEnabled()) {
506: myLoggingService.info(getAgentIdentifier()
507: + " no overlaps, requestedTimeSpan = "
508: + requestedTimeSpan
509: + " available schedule "
510: + currentAvailability);
511: }
512: }
513: }
514:
515: if ((earliest == TimeSpan.MAX_VALUE)
516: || (latest == TimeSpan.MIN_VALUE)) {
517: return null;
518: } else {
519: MutableTimeSpan returnTimeSpan = new MutableTimeSpan();
520: returnTimeSpan.setTimeSpan(earliest, latest);
521: return returnTimeSpan;
522: }
523: }
524:
525: private HashMap copyPreferences(Collection preferences) {
526: HashMap preferenceMap = new HashMap(preferences.size());
527:
528: for (Iterator iterator = preferences.iterator(); iterator
529: .hasNext();) {
530: Preference original = (Preference) iterator.next();
531:
532: Preference copy = getFactory()
533: .newPreference(original.getAspectType(),
534: original.getScoringFunction(),
535: original.getWeight());
536: preferenceMap.put(new Integer(copy.getAspectType()), copy);
537: }
538:
539: return preferenceMap;
540: }
541: }
|