001: /*
002: * <copyright>
003: *
004: * Copyright 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: package org.cougaar.pizza.plugin;
027:
028: import org.cougaar.core.blackboard.IncrementalSubscription;
029:
030: import org.cougaar.pizza.Constants;
031: import org.cougaar.pizza.plugin.util.RoleWithBlacklistScorer;
032:
033: import org.cougaar.planning.ldm.asset.Asset;
034: import org.cougaar.planning.ldm.plan.PrepositionalPhrase;
035: import org.cougaar.planning.ldm.plan.Role;
036: import org.cougaar.planning.ldm.plan.Task;
037:
038: import org.cougaar.servicediscovery.description.ServiceClassification;
039: import org.cougaar.servicediscovery.description.ServiceDescription;
040: import org.cougaar.servicediscovery.description.ServiceInfoScorer;
041: import org.cougaar.servicediscovery.plugin.SimpleSDClientPlugin;
042:
043: import org.cougaar.util.UnaryPredicate;
044:
045: import java.util.ArrayList;
046: import java.util.Collection;
047: import java.util.Enumeration;
048: import java.util.Iterator;
049:
050: /**
051: * ServiceDiscovery ClientPlugin, responsible for initiating queries for services,
052: * taking the resulting service pointer, and sending a Relay to the Provider requesting service.
053: *<p>
054: * Service Discovery is initiated by receiving a Find Providers task, and looking for the single Role
055: * indicated on the AS Prepositional Phrase, possibly excluding the Providers listed in the NOT
056: * Prepositional Phrase. Sends a Disposition on the FindProviders Task when it gets a Relationship
057: * with a provider for the service.
058: *<p>
059: * This is an extension of the SimpleSDClientPlugin that uses the pizza Domain constants and
060: * specically forbids using providers listed in the Find Providers Task. Use this as an example
061: * of how you can extend the SimpleSDClientPlugin for your own application.
062: *<p>
063: * Limitations: not quiescent aware, doesn't handle time-phased relationships,
064: * not guaranteed to work with persistence and restarts, and assumes that providers
065: * will not revoke relationships or otherwise change their mind.
066: */
067: public class SDClientPlugin extends SimpleSDClientPlugin {
068: /////////
069: // Methods to get the query to the Matchmaker...
070:
071: /**
072: * Return Collection of the Entity in the indirect Object of the {@link Constants.Prepositions.NOT} Prep Phrases,
073: * indicating a Provider not to return from Service Discovery.
074: *
075: * @param findProvidersTask Task requesting Service Discovery
076: * @return Collection of Provider names not to use in Service Discovery, possibly empty
077: */
078: private Collection getExcludedProviders(Task findProvidersTask) {
079: Enumeration phrases = findProvidersTask
080: .getPrepositionalPhrases();
081: ArrayList providers = new ArrayList();
082: // Loop over Prepositional Phrases on the Task
083: while (phrases.hasMoreElements()) {
084: PrepositionalPhrase nPhrase = (PrepositionalPhrase) phrases
085: .nextElement();
086: // If this Phrase's preposition is NOT
087: if (nPhrase != null
088: && org.cougaar.pizza.Constants.Prepositions.NOT
089: .equals(nPhrase.getPreposition())) {
090: // Then add the Item ID of the Indirect Object (ie String name of the Provider) to the collection
091: providers.add(((Asset) nPhrase.getIndirectObject())
092: .getItemIdentificationPG()
093: .getItemIdentification());
094: }
095: }
096:
097: // The resulting collection (possibly empty) is the providers not to use
098: return providers;
099: }
100:
101: /**
102: * Create a scoring function to weigh different services registered in the YP, for use
103: * by the Matchmaker.
104: * In this case, create a function that requires the given role, and forbids any providers
105: * named by the given Task.
106: *<p>
107: * Extenders of this plugin may over-ride this method to use a different function.
108: *
109: * @param role the Role to look for
110: * @param fpTask The FindProviders task this will satisfy
111: * @return the scoring function to hand the Matchmaker
112: */
113: protected ServiceInfoScorer getServiceInfoScorer(Role role,
114: Task fpTask) {
115: // Create a Service Scorer that looks for a provider with the given role,
116: // excluding any providers specifically excluded on the FindProviders Task.
117: // Note that another way to do this would be to exclude any providers currently supplying this Role
118: Collection excludes = getExcludedProviders(fpTask);
119: if (myLoggingService.isInfoEnabled())
120: myLoggingService.info("Will excluded providers: "
121: + excludes);
122: return new RoleWithBlacklistScorer(role, excludes);
123: }
124:
125: ///////////
126: // Support methods for tasking Matchmaker response and requesting the service from the Provider
127:
128: /**
129: * Retrieve the Role that the Provider is offering out of the ServiceDescription.
130: * Note that this assumes the role is under the CommercialServiceScheme, using the
131: * Domain's Constants file. Extenders will over-ride this method.
132: *
133: * @param serviceDescription The Description of the Service as advertised in the YP.
134: * @return the Role advertised by the Provider, or null if none found.
135: */
136: protected Role getRole(ServiceDescription serviceDescription) {
137: // A serviceDescription may have multiple Classifications
138: for (Iterator iterator = serviceDescription
139: .getServiceClassifications().iterator(); iterator
140: .hasNext();) {
141: ServiceClassification serviceClassification = (ServiceClassification) iterator
142: .next();
143: // We have placed the Roles providers are registering in the CommercialServiceScheme
144: // (see pizza/data/taxonomies)
145: if (serviceClassification
146: .getClassificationSchemeName()
147: .equals(
148: org.cougaar.pizza.Constants.UDDIConstants.COMMERCIAL_SERVICE_SCHEME)) {
149: Role role = Role.getRole(serviceClassification
150: .getClassificationName());
151: return role;
152: }
153: }
154: return null;
155: }
156:
157: ////////////////
158: // Now the Unary Predicates for use with subscriptions.
159:
160: /**
161: * Predicate to get the FindProviders Tasks. In the off-chance that your verb is
162: * slightly different, you can over-ride this method to point to your
163: * domain-specific Verb Constant.
164: *<b>
165: * Note that it is not a constant, just so it can be over-ridden.
166: */
167: protected UnaryPredicate getFindProvidersPredicate() {
168: return new UnaryPredicate() {
169: public boolean execute(Object o) {
170: if (o instanceof Task) {
171: return ((Task) o)
172: .getVerb()
173: .equals(
174: org.cougaar.pizza.Constants.Verbs.FIND_PROVIDERS);
175: } else {
176: return false;
177: }
178: }
179: };
180: }
181: }
|