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.logistics.plugin.servicediscovery;
028:
029: import org.cougaar.core.blackboard.IncrementalSubscription;
030: import org.cougaar.core.service.LoggingService;
031:
032: import org.cougaar.planning.ldm.plan.Disposition;
033: import org.cougaar.planning.ldm.plan.PlanElement;
034: import org.cougaar.planning.ldm.plan.Preference;
035: import org.cougaar.planning.ldm.plan.Role;
036: import org.cougaar.planning.ldm.plan.ScoringFunction;
037: import org.cougaar.planning.ldm.plan.Task;
038: import org.cougaar.planning.ldm.plan.Verb;
039: import org.cougaar.planning.plugin.legacy.SimplePlugin;
040: import org.cougaar.planning.plugin.util.PluginHelper;
041: import org.cougaar.util.log.Logger;
042: import org.cougaar.util.log.Logging;
043: import org.cougaar.util.TimeSpan;
044: import org.cougaar.util.TimeSpans;
045: import org.cougaar.util.TimeSpanSet;
046: import org.cougaar.util.UnaryPredicate;
047:
048: //import org.cougaar.glm.ldm.Constants;
049:
050: import org.cougaar.servicediscovery.SDFactory;
051:
052: import org.cougaar.servicediscovery.description.LineageEchelonScorer;
053: import org.cougaar.servicediscovery.description.Lineage;
054: import org.cougaar.servicediscovery.description.MMRoleQuery;
055: import org.cougaar.servicediscovery.description.ScoredServiceDescription;
056: import org.cougaar.servicediscovery.description.ServiceContract;
057: import org.cougaar.servicediscovery.description.ServiceDescription;
058: import org.cougaar.servicediscovery.description.ServiceInfo;
059: import org.cougaar.servicediscovery.description.ServiceRequest;
060: import org.cougaar.servicediscovery.description.TimeInterval;
061: import org.cougaar.servicediscovery.plugin.SDClientPlugin;
062: import org.cougaar.servicediscovery.transaction.MMQueryRequest;
063: import org.cougaar.servicediscovery.transaction.ServiceContractRelay;
064:
065: import java.util.ArrayList;
066: import java.util.Collection;
067: import java.util.Collections;
068: import java.util.Comparator;
069: import java.util.Date;
070: import java.util.Iterator;
071: import java.util.HashMap;
072:
073: import java.util.SortedSet;
074: import java.util.TreeSet;
075:
076: import org.cougaar.mlm.plugin.organization.GLSConstants;
077: import org.cougaar.planning.ldm.plan.PrepositionalPhrase;
078:
079: public class ALDynamicSDClientPlugin extends SDClientPlugin implements
080: GLSConstants {
081: private HashMap myServiceRequestHistories;
082:
083: public static void main(String[] args) {
084: ServiceRequestRecord srr = new ServiceRequestRecord("Test",
085: TimeSpans.getSpan(1000, 2000));
086: ServiceRequestRecord srr2 = new ServiceRequestRecord("Test",
087: TimeSpans.getSpan(2000, 3000));
088: ServiceRequestHistory srh = new ServiceRequestHistory(null,
089: TimeSpans.getSpan(1000, 3000), srr);
090: srh.addRequest(srr2);
091: System.out.println(srh.containsRequest("Test", TimeSpans
092: .getSpan(1000, 2000)));
093: //true
094: System.out.println(srh.containsRequest("Test", TimeSpans
095: .getSpan(1000, 3000)));
096: //true
097: System.out.println(srh.containsRequest("Test", TimeSpans
098: .getSpan(1500, 2500)));
099: //true
100: System.out.println(srh.containsRequest("Test", TimeSpans
101: .getSpan(500, 2500)));
102: //false
103: System.out.println(srh.containsRequest("XS", TimeSpans.getSpan(
104: 1000, 2000)));
105: //false
106: }
107:
108: protected void setupSubscriptions() {
109: myServiceRequestHistories = new HashMap();
110: super .setupSubscriptions();
111: }
112:
113: /**
114: * overrides the superclass to deal with service request histories
115: */
116: protected void handleChangedServiceContractRelays(
117: Collection changedRelays) {
118: if (myLoggingService.isDebugEnabled()) {
119: myLoggingService.debug(getAgentIdentifier()
120: + " handleChangedServiceContractRelays "
121: + changedRelays.size());
122: }
123:
124: for (Iterator iterator = changedRelays.iterator(); iterator
125: .hasNext();) {
126: ServiceContractRelay relay = (ServiceContractRelay) iterator
127: .next();
128:
129: // Only interested if we are the client
130: if (!(relay.getClient().equals(getSelfOrg()))) {
131: continue;
132: }
133:
134: ServiceContract contract = relay.getServiceContract();
135: Role role = contract.getServiceRole();
136:
137: //if the role is now completely covered, discard the history
138: if (checkProviderCompletelyCovered(role)) {
139: if (myLoggingService.isDebugEnabled()) {
140: myLoggingService.debug(getAgentIdentifier()
141: + ": handleChangedServiceContractRelays() "
142: + "completely covered for " + role);
143: }
144: myServiceRequestHistories.remove(role);
145: } else {
146:
147: //if your service contract got revoked, or your requested
148: //service time interval was not satistied, do a new service query
149: if (myLoggingService.isDebugEnabled()) {
150: myLoggingService
151: .debug(getAgentIdentifier()
152: + " revoked "
153: + contract.isRevoked()
154: + " !satisfied "
155: + !timeIntervalRequestedCompletelySatisfied(relay));
156: }
157:
158: // Contract timespan does not == requested timespan
159: if ((contract.isRevoked() || !timeIntervalRequestedCompletelySatisfied(relay))) {
160: handleModifiedServiceContract(relay);
161: } else {
162: // We know from checkProviderCovered that service is not covered
163: // Ping execute so that we query for missing services
164: setNeedToFindProviders(true);
165: wake();
166: }
167: }
168: }
169: }
170:
171: private ServiceRequestHistory augmentServiceRequestHistory(
172: ServiceContractRelay relay, TimeSpan requestedTimeInterval) {
173:
174: if (requestedTimeInterval == null) {
175: myLoggingService
176: .debug(getAgentIdentifier()
177: + " service request to "
178: + relay.getProviderName()
179: + " for "
180: + relay.getServiceRequest()
181: .getServiceRole()
182: + " does not have valid start/end time preferences.");
183: }
184:
185: ServiceRequestRecord srr = new ServiceRequestRecord(relay
186: .getProviderName(), requestedTimeInterval);
187:
188: //if this request is not in the history (because it previously
189: //completely satisfied the request) put it in
190: Role role = relay.getServiceContract().getServiceRole();
191: ServiceRequestHistory srh = (ServiceRequestHistory) myServiceRequestHistories
192: .get(role);
193: if (srh == null) {
194: if (myLoggingService.isDebugEnabled()) {
195: myLoggingService
196: .debug(getAgentIdentifier()
197: + " handleChangedServiceContractRelays, put into history "
198: + relay.getProviderName() + " " + role);
199: }
200:
201: srh = new ServiceRequestHistory(role,
202: requestedTimeInterval, srr);
203: myServiceRequestHistories.put(role, srh);
204:
205: if (myLoggingService.isDebugEnabled()) {
206: for (Iterator it = myServiceRequestHistories.keySet()
207: .iterator(); it.hasNext();) {
208: Role key = (Role) it.next();
209: if (myLoggingService.isDebugEnabled()) {
210: myLoggingService.debug("key " + key);
211: }
212: }
213: }
214: } else {
215: //Add new service request history
216: srh.addRequest(srr);
217: }
218:
219: return srh;
220: }
221:
222: /**
223: * returns true if the relay's request time interval is a subset of the
224: * relay's contract time interval
225: */
226: private boolean timeIntervalRequestedCompletelySatisfied(
227: ServiceContractRelay relay) {
228: if (relay.getServiceContract() == null) {
229: return false;
230: }
231:
232: TimeSpan requested = SDFactory.getTimeSpanFromPreferences(relay
233: .getServiceRequest().getServicePreferences());
234: TimeSpan provided = SDFactory.getTimeSpanFromPreferences(relay
235: .getServiceContract().getServicePreferences());
236:
237: if ((requested == null) || (provided == null)) {
238: return false;
239: } else {
240: return ((requested.getStartTime() >= provided
241: .getStartTime()) && (requested.getEndTime() <= provided
242: .getEndTime()));
243: }
244: }
245:
246: /**
247: * overrides superclass to deal with service request histories
248: */
249: protected void requestServiceContract(
250: ServiceDescription serviceDescription, TimeSpan interval) {
251: super .requestServiceContract(serviceDescription, interval);
252: String providerName = serviceDescription.getProviderName();
253: Role role = getRole(serviceDescription);
254:
255: //add to your service request history
256: ServiceRequestRecord srr = new ServiceRequestRecord(
257: providerName, interval);
258: ServiceRequestHistory history;
259:
260: if (myServiceRequestHistories.containsKey(role)) {
261: history = (ServiceRequestHistory) myServiceRequestHistories
262: .get(role);
263: history.addRequest(srr);
264: } else {
265: history = new ServiceRequestHistory(role, interval, srr);
266: }
267:
268: myServiceRequestHistories.put(role, history);
269: }
270:
271: /**
272: * overrides the superclass to deal with service request histories
273: */
274: protected void handleRequestWithNoRemainingProviderOption(
275: Role role, TimeSpan currentInterval) {
276: //this means you have a time interval where you have exhausted all possible
277: //providers. Log a warning.
278: if (myLoggingService.isWarnEnabled()) {
279: myLoggingService
280: .warn(getAgentIdentifier()
281: + " failed to contract with "
282: + role
283: + " for time period from "
284: + new java.util.Date(currentInterval
285: .getStartTime())
286: + " to "
287: + new java.util.Date(currentInterval
288: .getEndTime()));
289: }
290: //Flush the request history.
291: myServiceRequestHistories.remove(role);
292: //set the automatic retry
293: activateAutomaticFindProviderRetry();
294: }
295:
296: /**
297: * overrides the superclass
298: * reorder ties by provider name using the scored service description comparator
299: */
300: protected Collection reorderAnyTiedServiceDescriptions(
301: ArrayList scoredServiceDescriptions) {
302: ArrayList sortedSSD = new ArrayList(scoredServiceDescriptions);
303: Collections.sort(sortedSSD,
304: new ScoredServiceDescriptionComparator());
305: return sortedSSD;
306: }
307:
308: /**
309: * Return true if according to your service request history, you have already
310: * asked this provider for this complete time interval for this role.
311: * Overrides the superclass to deal with service request history.
312: */
313: protected boolean alreadyAskedForContractWithProvider(Role role,
314: String providerName, TimeSpan timeInterval) {
315:
316: if (myLoggingService.isDebugEnabled()) {
317: myLoggingService.debug(getAgentIdentifier()
318: + " alreadyAskedForContractWithProvider check "
319: + providerName + " " + role);
320: }
321: //what if part of the current time interval was requested but another part(s)
322: //wasn't? (should return false, because if there is any uncovered part, you
323: //want to make the request)
324:
325: //search for all myServiceRequestHistories with matching role
326: //there should be one or none
327: ServiceRequestHistory srh = (ServiceRequestHistory) myServiceRequestHistories
328: .get(role);
329: if (srh != null) {
330: boolean ret = srh.containsRequest(providerName,
331: timeInterval);
332: if (myLoggingService.isDebugEnabled()) {
333: myLoggingService
334: .debug(getAgentIdentifier()
335: + " alreadyAskedForContractWithProvider "
336: + ret);
337: }
338: return ret;
339: } else if (myLoggingService.isDebugEnabled()) {
340: myLoggingService
341: .debug(getAgentIdentifier()
342: + " alreadyAskedForContractWithProvider srh is null");
343: Iterator it = myServiceRequestHistories.keySet().iterator();
344: while (it.hasNext()) {
345: Role key = (Role) it.next();
346: if (myLoggingService.isDebugEnabled()) {
347: myLoggingService.debug("key " + key);
348: }
349: }
350: }
351:
352: return false;
353: }
354:
355: /**
356: * requires that start <= end
357: * Return a collection of all time intervals between desiredStart and
358: * desiredEnd that are not covered by existing service contracts or
359: * outstanding requests for this role.
360: * Overrides superclass to deal with provider relationships with time
361: * spans not the default.
362: */
363: protected Collection getCurrentlyUncoveredIntervalsWithoutOutstandingRequests(
364: long desiredStart, long desiredEnd, Role role) {
365:
366: Collection stillNeeded = getCurrentlyUncoveredIntervals(
367: desiredStart, desiredEnd, role);
368:
369: //go through the existing service contracts and remove the
370: //time periods that have been requested but not yet responded to
371: for (Iterator relayIterator = myServiceContractRelaySubscription
372: .iterator(); relayIterator.hasNext();) {
373: ServiceContractRelay relay = (ServiceContractRelay) relayIterator
374: .next();
375: if (!relay.getClient().equals(getSelfOrg())) {
376: continue;
377: }
378:
379: if (relay.getServiceContract() == null
380: && relay.getServiceRequest().getServiceRole()
381: .equals(role)) {
382:
383: TimeSpan requestedTimeInterval = SDFactory
384: .getTimeSpanFromPreferences(relay
385: .getServiceRequest()
386: .getServicePreferences());
387:
388: stillNeeded = TimeInterval.removeInterval(
389: requestedTimeInterval, stillNeeded);
390: }
391: }
392:
393: return stillNeeded;
394: }
395:
396: //requires that start <= end
397: //returns a collection of intervals between neededStartTime and
398: // neededEndTime which is not covered for the specified role
399: private Collection getCurrentlyUncoveredIntervals(
400: long desiredStart, long desiredEnd, Role role) {
401:
402: ArrayList desiredCoverageIntervals = new ArrayList();
403: desiredCoverageIntervals.add(TimeSpans.getSpan(desiredStart,
404: desiredEnd));
405: Collection stillNeeded = desiredCoverageIntervals;
406:
407: //go through the existing service contracts and remove the time
408: //periods which are covered already
409: for (Iterator relayIterator = myServiceContractRelaySubscription
410: .iterator(); relayIterator.hasNext();) {
411: ServiceContractRelay relay = (ServiceContractRelay) relayIterator
412: .next();
413: if (!relay.getClient().equals(getSelfOrg())) {
414: continue;
415: }
416:
417: ServiceContract contract = relay.getServiceContract();
418:
419: if ((contract != null) && (!contract.isRevoked())
420: && (contract.getServiceRole().equals(role))) {
421:
422: TimeSpan providedTimeInterval = SDFactory
423: .getTimeSpanFromPreferences(relay
424: .getServiceContract()
425: .getServicePreferences());
426:
427: if (providedTimeInterval == null) {
428: if (myLoggingService.isDebugEnabled()) {
429: myLoggingService
430: .debug(getAgentIdentifier()
431: + " getCurrentlyUncoveredIntervals: "
432: + " contract with "
433: + relay.getProviderName()
434: + " for "
435: + role
436: + " does not have a valid time period.");
437: }
438: } else {
439: if (myLoggingService.isDebugEnabled()) {
440: myLoggingService.debug(getAgentIdentifier()
441: + " getCurrentlyUncoveredIntervals: "
442: + " contract with "
443: + relay.getProviderName() + " for "
444: + role + " runs "
445: + providedTimeInterval.getStartTime()
446: + " to "
447: + providedTimeInterval.getEndTime());
448: }
449: // If contract specifies a valid time range, remove it.
450: stillNeeded = TimeInterval.removeInterval(
451: providedTimeInterval, stillNeeded);
452: }
453: }
454: }
455:
456: return stillNeeded;
457: }
458:
459: /**
460: * If there is a current request history for this role, check the
461: * time interval of it. Otherwise, check the default time interval.
462: * Return true if this role is completely covered by service contracts or
463: * outstanding requests
464: * Override superclass to deal with potential provider relationships
465: * that have start/end time not equal to default start/end.
466: */
467: protected boolean checkProviderCompletelyCoveredOrRequested(
468: Role role) {
469: TimeSpan opconTimeSpan = getOPCONTimeSpan();
470: Collection c = getCurrentlyUncoveredIntervalsWithoutOutstandingRequests(
471: opconTimeSpan.getStartTime(), opconTimeSpan
472: .getEndTime(), role);
473:
474: //check the personal history time interval (if it exists)
475: //instead of the default interval
476: ServiceRequestHistory srh = (ServiceRequestHistory) myServiceRequestHistories
477: .get(role);
478: if (srh != null) {
479: c = getCurrentlyUncoveredIntervalsWithoutOutstandingRequests(
480: srh.requestedTimeInterval.getStartTime(),
481: srh.requestedTimeInterval.getEndTime(), role);
482: }
483:
484: for (Iterator uncovered = c.iterator(); uncovered.hasNext();) {
485: TimeSpan current = (TimeSpan) uncovered.next();
486: if (current.getStartTime() < current.getEndTime()) {
487: if (myLoggingService.isDebugEnabled()) {
488: myLoggingService
489: .debug(getAgentIdentifier()
490: + " checkProviderCompletelyCoveredOrRequested has millisec difference of: "
491: + (current.getEndTime() - current
492: .getStartTime())
493: + " start "
494: + current.getStartTime() + " end "
495: + current.getEndTime());
496:
497: }
498: return false;
499: }
500: }
501: return true;
502: }
503:
504: /**
505: * If there is a current request history for this role, check the
506: * time interval of it. Otherwise, check the default time interval.
507: * Return true if the interval is covered by non-revoked service contracts.
508: * Override superclass to deal with potential provider relationships
509: * that have start/end time not equal to default start/end.
510: */
511: protected boolean checkProviderCompletelyCovered(Role role) {
512: TimeSpan opconTimeSpan = getOPCONTimeSpan();
513: Collection c = getCurrentlyUncoveredIntervals(opconTimeSpan
514: .getStartTime(), opconTimeSpan.getEndTime(), role);
515:
516: if (myLoggingService.isDebugEnabled()) {
517: myLoggingService.debug(getAgentIdentifier()
518: + " checkProviderCompletelyCovered: "
519: + " uncovered intervals for " + role + " = " + c);
520: }
521:
522: //check the personal history time interval (if it exists)
523: //instead of the default interval
524: ServiceRequestHistory srh = (ServiceRequestHistory) myServiceRequestHistories
525: .get(role);
526: if (srh != null) {
527: c = getCurrentlyUncoveredIntervals(
528: srh.requestedTimeInterval.getStartTime(),
529: srh.requestedTimeInterval.getEndTime(), role);
530:
531: if (myLoggingService.isDebugEnabled()) {
532: myLoggingService
533: .debug(getAgentIdentifier()
534: + " checkProviderCompletelyCovered: "
535: + " uncovered intervals from service request history "
536: + srh + " = " + c);
537: }
538: }
539:
540: for (Iterator uncovered = c.iterator(); uncovered.hasNext();) {
541: TimeSpan current = (TimeSpan) uncovered.next();
542:
543: if (current.getStartTime() < current.getEndTime()) {
544: if (myLoggingService.isDebugEnabled()) {
545: myLoggingService
546: .debug(getAgentIdentifier()
547: + " checkProviderCompletelyCovered has millisec difference of: "
548: + (current.getEndTime() - current
549: .getStartTime())
550: + " start "
551: + current.getStartTime() + " end "
552: + current.getEndTime()
553: + " for role " + role);
554: }
555: return false;
556: }
557: }
558: return true;
559: }
560:
561: protected void handleModifiedServiceContract(
562: ServiceContractRelay relay) {
563: ServiceContract contract = relay.getServiceContract();
564: Role role = contract.getServiceRole();
565:
566: if (myLoggingService.isDebugEnabled()) {
567: myLoggingService
568: .debug(getAgentIdentifier()
569: + " queryServices because a service contract was revoked or did not satisfy the request for "
570: + role);
571: }
572:
573: TimeSpan requestedTimeInterval = SDFactory
574: .getTimeSpanFromPreferences(relay.getServiceRequest()
575: .getServicePreferences());
576:
577: ServiceRequestHistory srh = augmentServiceRequestHistory(relay,
578: requestedTimeInterval);
579:
580: if (myLoggingService.isDebugEnabled()) {
581: myLoggingService.debug(getAgentIdentifier()
582: + " do another queryServices for " + role);
583: }
584:
585: TimeSpan providedTimeInterval = SDFactory
586: .getTimeSpanFromPreferences(contract
587: .getServicePreferences());
588:
589: Collection uncoveredTimeIntervals = TimeInterval
590: .removeInterval(providedTimeInterval,
591: requestedTimeInterval);
592:
593: String minimumEchelon = getMinimumEchelon(role);
594:
595: for (Iterator uncoveredIterator = uncoveredTimeIntervals
596: .iterator(); uncoveredIterator.hasNext();) {
597:
598: TimeSpan uncoveredInterval = (TimeSpan) uncoveredIterator
599: .next();
600:
601: Collection opconIntervals = getOPCONSchedule()
602: .intersectingSet(uncoveredInterval);
603: if (opconIntervals.isEmpty()) {
604: myLoggingService.error(getAgentIdentifier()
605: + " handleChangedServiceContractRelays: "
606: + " no OPCON lineage on blackboard for "
607: + new Date(uncoveredInterval.getStartTime())
608: + " to "
609: + new Date(uncoveredInterval.getEndTime())
610: + ". Unable to generate MMRoleQuery for "
611: + role);
612: continue;
613: } else if (!continuousCoverage(uncoveredInterval,
614: new TimeSpanSet(opconIntervals))) {
615: myLoggingService.error(getAgentIdentifier()
616: + " handleChangedServiceContractRelays: "
617: + " gap in OPCON coverage at some point in "
618: + new Date(uncoveredInterval.getStartTime())
619: + " to "
620: + new Date(uncoveredInterval.getEndTime())
621: + ".");
622: }
623:
624: for (Iterator opconIterator = opconIntervals.iterator(); opconIterator
625: .hasNext();) {
626: TimeSpan opconInterval = (TimeSpan) opconIterator
627: .next();
628:
629: Lineage commandLineage = getCommandLineage(opconInterval);
630:
631: if (commandLineage != null) {
632: ArrayList arrayList = new ArrayList(1);
633: arrayList.add(TimeSpans
634: .getSpan(opconInterval.getStartTime(),
635: opconInterval.getEndTime()));
636:
637: LineageEchelonScorer serviceScorer = new ALLineageEchelonScorer(
638: commandLineage, getMinimumEchelon(role),
639: role, getAgentIdentifier().toString(), srh,
640: arrayList);
641:
642: queryServices(role, serviceScorer, opconInterval);
643: } else {
644: // Should be impossible
645: myLoggingService.error(getAgentIdentifier()
646: + " handleChangedServiceContractRelays: "
647: + " no OPCON lineage on blackboard for "
648: + new Date(opconInterval.getStartTime())
649: + " to "
650: + new Date(opconInterval.getEndTime())
651: + " Unable to generate MMRoleQuery for "
652: + role);
653: }
654: }
655: //publishRemove(relay);
656: }
657: }
658:
659: private void activateAutomaticFindProviderRetry() {
660: //todo: set a daily alarm
661: }
662:
663: private static class ServiceRequestHistory {
664:
665: Role requestedRole;
666: TimeSpan requestedTimeInterval;
667: ArrayList serviceRequestRecords;
668:
669: ServiceRequestHistory(Role requestedRole,
670: TimeSpan requestedTimeInterval,
671: ServiceRequestRecord firstRequestRecord) {
672: this .requestedRole = requestedRole;
673: this .requestedTimeInterval = requestedTimeInterval;
674: serviceRequestRecords = new ArrayList();
675: serviceRequestRecords.add(firstRequestRecord);
676: }
677:
678: void addRequest(ServiceRequestRecord srr) {
679: serviceRequestRecords.add(srr);
680: }
681:
682: //start with timeInterval
683: //for every ServiceRequestRecord with matching provider, subtract that time
684: //interval
685: //at the end, see if there is anything remaining
686: //if so, return false
687: boolean containsRequest(String providerName,
688: TimeSpan requestedTimeInterval) {
689: TimeSpan unrequested = TimeSpans.getSpan(
690: requestedTimeInterval.getStartTime(),
691: requestedTimeInterval.getEndTime());
692: ArrayList unRequestedTimeIntervals = new ArrayList();
693: unRequestedTimeIntervals.add(unrequested);
694:
695: for (Iterator requests = serviceRequestRecords.iterator(); requests
696: .hasNext();) {
697: ServiceRequestRecord current = (ServiceRequestRecord) requests
698: .next();
699: ArrayList newUnrequestedTimeIntervals = new ArrayList();
700:
701: if (current.providerName.equals(providerName)) {
702: for (Iterator oldUnrequested = unRequestedTimeIntervals
703: .iterator(); oldUnrequested.hasNext();) {
704: TimeSpan oldCurrent = (TimeSpan) oldUnrequested
705: .next();
706: newUnrequestedTimeIntervals.addAll(TimeInterval
707: .removeInterval(
708: current.requestedTimeInterval,
709: oldCurrent));
710: }
711: unRequestedTimeIntervals = newUnrequestedTimeIntervals;
712: }
713: }
714:
715: if (unRequestedTimeIntervals.isEmpty()) {
716: return true;
717: } else {
718: for (Iterator unrequestedIterator = unRequestedTimeIntervals
719: .iterator(); unrequestedIterator.hasNext();) {
720: TimeSpan current = (TimeSpan) unrequestedIterator
721: .next();
722: //may need to add an epsilon ball around each time
723: if (current.getStartTime() != current.getEndTime()) {
724: return false;
725: }
726: }
727: return true;
728: }
729: }
730: }
731:
732: protected static class ServiceRequestRecord {
733: String providerName;
734: TimeSpan requestedTimeInterval;
735:
736: ServiceRequestRecord(String providerName,
737: TimeSpan requestedTimeInterval) {
738: this .providerName = providerName;
739: this .requestedTimeInterval = requestedTimeInterval;
740: }
741: }
742:
743: protected static class ScoredServiceDescriptionComparator implements
744: java.util.Comparator {
745:
746: public int compare(Object first, Object second) {
747: if (!(first instanceof ScoredServiceDescription)
748: && !(second instanceof ScoredServiceDescription)) {
749: throw new ClassCastException(
750: "Both objects must be ScoredServiceDescriptions");
751: } else {
752: ScoredServiceDescription firstSSD = (ScoredServiceDescription) first;
753: ScoredServiceDescription secondSSD = (ScoredServiceDescription) second;
754: if (firstSSD.getScore() > secondSSD.getScore()) {
755: return 1;
756: } else if (firstSSD.getScore() < secondSSD.getScore()) {
757: return -1;
758: } else {
759: return firstSSD.getProviderName().compareTo(
760: secondSSD.getProviderName());
761: }
762: }
763: }
764: }
765:
766: protected static class ALLineageEchelonScorer extends
767: LineageEchelonScorer {
768: private static Logger logger = Logging
769: .getLogger(ALLineageEchelonScorer.class);
770:
771: private transient ServiceRequestHistory serviceRequestHistory;
772: private transient Collection uncoveredTimeIntervals;
773: private transient String clientName;
774:
775: public ALLineageEchelonScorer() {
776: super ();
777: }
778:
779: public ALLineageEchelonScorer(Lineage lineage,
780: String minimumEchelon, Role role, String cn,
781: ServiceRequestHistory srh, Collection uti) {
782: super (lineage, minimumEchelon, role);
783: clientName = cn;
784: uncoveredTimeIntervals = uti;
785: serviceRequestHistory = srh;
786: }
787:
788: public int scoreServiceInfo(ServiceInfo serviceInfo) {
789:
790: if (serviceRequestHistory == null) {
791: // Nothing to evaluate against
792: return super .scoreServiceInfo(serviceInfo);
793: }
794:
795: String providerName = serviceInfo.getProviderName();
796:
797: for (Iterator iterator = uncoveredTimeIntervals.iterator(); iterator
798: .hasNext();) {
799: TimeSpan timeInterval = (TimeSpan) iterator.next();
800:
801: if (!serviceRequestHistory.containsRequest(
802: providerName, timeInterval)) {
803: if (logger.isDebugEnabled()) {
804: logger.debug(clientName
805: + " ALLineageEchelonScorer passed "
806: + providerName + " for "
807: + new Date(timeInterval.getStartTime())
808: + " to "
809: + new Date(timeInterval.getEndTime()));
810: }
811: return super .scoreServiceInfo(serviceInfo);
812: }
813: }
814:
815: if (logger.isDebugEnabled()) {
816: logger.debug(clientName
817: + "ALLineageEchelonScorer returned -1 for "
818: + providerName);
819: }
820: // All intervals previously asked for
821: return -1;
822: }
823: }
824: }
|