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.adaptivity;
028:
029: import java.util.ArrayList;
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.List;
033: import java.util.Map;
034:
035: import org.cougaar.core.service.LoggingService;
036:
037: /**
038: * A container for Plays providing operations to constrain plays with
039: * {@link OperatingModePolicy OperatingModePolicy}s.
040: **/
041: public class Playbook {
042: private Play[] originalPlays = new Play[0];
043: private Play[] constrainedPlays = new Play[0];
044: private List constraints = new ArrayList();
045: private LoggingService logger;
046:
047: public Playbook(LoggingService logger) {
048: this .logger = logger;
049: }
050:
051: public synchronized void addConstraint(OperatingModePolicy omp) {
052: constraints.add(omp);
053: constrainPlays(omp);
054: }
055:
056: public synchronized void removeConstraint(OperatingModePolicy omp) {
057: constraints.remove(omp);
058: constrainPlays();
059: }
060:
061: public synchronized void setPlays(Play[] plays) {
062: originalPlays = plays;
063: constrainPlays();
064: }
065:
066: public synchronized Play[] getCurrentPlays() {
067: return constrainedPlays;
068: }
069:
070: private void constrainPlays() {
071: constrainedPlays = originalPlays;
072: for (Iterator i = constraints.iterator(); i.hasNext();) {
073: if (logger.isDebugEnabled()) {
074: logger.debug(constrainedPlays.length + " plays");
075: }
076: constrainPlays((OperatingModePolicy) i.next());
077: }
078: if (logger.isDebugEnabled()) {
079: logger.debug(constrainedPlays.length + " plays");
080: }
081: }
082:
083: /**
084: * Rewrite the playbook so that all the plays conform to a new
085: * OperatingModePolicy. The procedure is as follows: Scan the plays
086: * to find those plays that set OperatingModes overlapping with the
087: * OperatingModes of the policy. Then check if the conditions under
088: * which the policy applies overlap with the conditions under which
089: * the play applies. If there is overlap, rewrite the play as
090: * follows: Change the if clause of the original play so it applies
091: * only when the policy does not. Add a new play that applies when
092: * both the original play would have applied and the policy applies.
093: * The OperatingModes of the new play are those of the original play
094: * but with the ranges of values reduced to those values that the
095: * play and the policy have in common. If the set of allowed values
096: * for any OperatingMode is empty, then no play is added. Finally,
097: * the OperatingModePolicy itself is inserted as a Play to cover the
098: * cases where the policy applies, but no play does. It is not
099: * necessary to add any play predicates to this play, because by
100: * construction all plays are compatible with the policy.
101: **/
102: private void constrainPlays(OperatingModePolicy omp) {
103: List newConstrainedPlays = new ArrayList(
104: constrainedPlays.length);
105: ConstrainingClause ompIfClause = omp.getIfClause();
106: ConstraintPhrase[] ompConstraints = omp
107: .getOperatingModeConstraints();
108: Map ompModes = new HashMap();
109: // First, append the constraint itself as a Play so it dominates all following plays
110: newConstrainedPlays.add(new Play(omp.getIfClause(), omp
111: .getOperatingModeConstraints()));
112: for (int i = 0; i < ompConstraints.length; i++) {
113: ConstraintPhrase cp = ompConstraints[i];
114: String proxyName = cp.getProxyName();
115: ompModes.put(proxyName, cp);
116: }
117: for (int i = 0; i < constrainedPlays.length; i++) {
118: Play play = constrainedPlays[i];
119: ConstraintPhrase[] playConstraints = play
120: .getOperatingModeConstraints();
121: ConstraintPhrase[] newConstraints = null;
122: for (int j = 0; j < playConstraints.length; j++) {
123: ConstraintPhrase cp = playConstraints[j];
124: String proxyName = cp.getProxyName();
125: if (!ompModes.containsKey(proxyName)) {
126: if (newConstraints != null) {
127: newConstraints[j] = playConstraints[j]; // No conflict here
128: }
129: } else {
130: if (newConstraints == null) {
131: newConstraints = new ConstraintPhrase[playConstraints.length];
132: System.arraycopy(playConstraints, 0,
133: newConstraints, 0, j);
134: }
135: }
136: }
137: if (newConstraints == null) {
138: newConstrainedPlays.add(play); // No overlap. Keep the play as is
139: } else {
140: // First write a Play that applies when the original play
141: // applies, but the constraint policy does not apply
142: ConstrainingClause playIfClause = play.getIfClause();
143: ConstrainingClause newIfClause = new ConstrainingClause();
144: newIfClause.push(playIfClause);
145: newIfClause.push(ompIfClause);
146: newIfClause.push(BooleanOperator.NOT);
147: newIfClause.push(BooleanOperator.AND);
148: Play newPlay = new Play(newIfClause, playConstraints);
149: newConstrainedPlays.add(newPlay);
150:
151: // Now write a Play that applies when both the original play
152: // and the constraint policy apply
153: newIfClause = new ConstrainingClause();
154: newIfClause.push(playIfClause);
155: newIfClause.push(ompIfClause);
156: newIfClause.push(BooleanOperator.AND);
157: for (int j = 0; j < playConstraints.length; j++) {
158: if (newConstraints[j] != null)
159: continue; // Ok as is
160: ConstraintPhrase cp = playConstraints[j];
161: String proxyName = cp.getProxyName();
162: ConstraintPhrase ompConstraint = (ConstraintPhrase) ompModes
163: .get(proxyName);
164: OMCRangeList intersection = cp
165: .getAllowedValues()
166: .intersect(ompConstraint.getAllowedValues());
167: if (intersection.isEmpty()) {
168: // Completely incompatible. This could be bad. It means
169: // that a play designed to work well in some conditions
170: // has been completely disallowed by the policy over those
171: // conditions. We record the name of the operating mode
172: // for which no suitable was available and use the value
173: // specified by the policy.
174: if (logger.isWarnEnabled()) {
175: logger.warn("Policy " + omp
176: + " disallows all settings for "
177: + proxyName + " of play " + play);
178: }
179: newConstraints[j] = ompConstraint;
180: } else {
181: // Some values are still ok so use them
182: newConstraints[j] = new ConstraintPhrase(
183: proxyName, cp.getOperator(),
184: intersection);
185: }
186: }
187: newPlay = new Play(newIfClause, newConstraints);
188: newConstrainedPlays.add(newPlay);
189: }
190: }
191: constrainedPlays = (Play[]) newConstrainedPlays
192: .toArray(constrainedPlays);
193: }
194: }
|