001: /*
002: * <copyright>
003: *
004: * Copyright 2001-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.tools.csmart.recipe;
027:
028: import org.cougaar.core.component.ComponentDescription;
029: import org.cougaar.tools.csmart.core.cdata.ComponentData;
030: import org.cougaar.tools.csmart.core.cdata.GenericComponentData;
031: import org.cougaar.tools.csmart.core.db.PopulateDb;
032: import org.cougaar.tools.csmart.core.property.ConfigurableComponentPropertyAdapter;
033: import org.cougaar.tools.csmart.core.property.Property;
034: import org.cougaar.tools.csmart.core.property.PropertyEvent;
035: import org.cougaar.tools.csmart.core.property.range.IntegerRange;
036:
037: import java.io.Serializable;
038: import java.net.URL;
039: import java.sql.SQLException;
040: import java.util.Collections;
041: import java.util.Set;
042:
043: public class SpecificInsertionRecipe extends RecipeBase implements
044: Serializable {
045: private static final String DESCRIPTION_RESOURCE_NAME = "specific-insertion-recipe-description.html";
046: private static final String BACKUP_DESCRIPTION = "SpecificInsertionRecipe provides a method for inserting Components into an experiment";
047:
048: private static final String PROP_NAME = "Component Name";
049: private static final String PROP_NAME_DFLT = "";
050: private static final String PROP_NAME_DESC = "Class name of the component. (usually same as Class Name)";
051:
052: private static final String PROP_TYPE = "Type of Insertion";
053: private static final String PROP_TYPE_DFLT = ComponentData.PLUGIN;
054: private static final String PROP_TYPE_DESC = "Type of Component being inserted";
055:
056: private static final String PROP_CLASS = "Class Name";
057: private static final String PROP_CLASS_DFLT = "";
058: private static final String PROP_CLASS_DESC = "The complete class of of the Component.";
059:
060: // Hack Note:
061: // When the properties are read from the database, they are sorted.
062: // It is essential that the Number of Arguments property is read
063: // from the database before the actual arguments, or it will crash
064: // (Because number of args creates the arg props)
065: // This is handled now by naming the args as "Value.."
066:
067: private static final String PROP_ARGS = "Number of Arguments";
068: private static final Integer PROP_ARGS_DFLT = new Integer(0);
069: private static final String PROP_ARGS_DESC = "The number of arguments for this insertion.";
070:
071: private static final String PROP_TARGET_COMPONENT_QUERY = "Target Component Selection Query";
072: private static final String PROP_TARGET_COMPONENT_QUERY_DFLT = "recipeQuerySelectNothing";
073: private static final String PROP_TARGET_COMPONENT_QUERY_DESC = "The query name for selecting components to modify";
074:
075: private static final String PROP_PRIORITY = "Component Priority";
076: private static final String PROP_PRIORITY_DFLT = ComponentDescription
077: .priorityToString(ComponentDescription.PRIORITY_STANDARD);
078: public static final String PROP_PRIORITY_DESC = "Load Priority of the component in it's container relative to other child components";
079:
080: private Property propName;
081: private Property propType;
082: private Property propClass;
083: private Property propArgs;
084: private Property propPriority;
085: private Property propTargetComponentQuery;
086: private Property[] variableProps = null;
087:
088: public SpecificInsertionRecipe() {
089: super ("Specific Component Recipe");
090: }
091:
092: public SpecificInsertionRecipe(String name) {
093: super (name);
094: }
095:
096: public void initProperties() {
097: propName = addProperty(PROP_NAME, PROP_NAME_DFLT);
098: propName.setToolTip(PROP_NAME_DESC);
099:
100: propType = addComponentTypeProperty(PROP_TYPE, PROP_TYPE_DFLT);
101: propType.setToolTip(PROP_TYPE_DESC);
102:
103: propClass = addProperty(PROP_CLASS, PROP_CLASS_DFLT);
104: propClass.setToolTip(PROP_CLASS_DESC);
105:
106: propArgs = addProperty(PROP_ARGS, PROP_ARGS_DFLT);
107: propArgs
108: .addPropertyListener(new ConfigurableComponentPropertyAdapter() {
109: public void propertyValueChanged(PropertyEvent e) {
110: // log.debug("propArgs listener fired with old val " + e.getPreviousValue().toString() + " and new: " + e.getProperty().getValue().toString() + " for Property " + e.getProperty().getName().toString(), new Throwable());
111: updatePropCount((Integer) e.getProperty()
112: .getValue());
113: }
114: });
115: propArgs.setToolTip(PROP_ARGS_DESC);
116: propArgs.setAllowedValues(Collections
117: .singleton(new IntegerRange(0, Integer.MAX_VALUE)));
118: propPriority = addPriorityProperty(PROP_PRIORITY,
119: PROP_PRIORITY_DFLT);
120: propPriority.setToolTip(PROP_PRIORITY_DESC);
121:
122: propTargetComponentQuery = addRecipeQueryProperty(
123: PROP_TARGET_COMPONENT_QUERY,
124: PROP_TARGET_COMPONENT_QUERY_DFLT);
125: propTargetComponentQuery
126: .setToolTip(PROP_TARGET_COMPONENT_QUERY_DESC);
127:
128: }
129:
130: /**
131: * Gets the name of the html help file for this component.
132: *
133: * @return an <code>URL</code> value
134: */
135: public URL getDescription() {
136: return getClass().getResource(DESCRIPTION_RESOURCE_NAME);
137: }
138:
139: private Property addComponentTypeProperty(String name, String dflt) {
140: Property prop = addProperty(new ComponentTypeProperty(this ,
141: name, dflt));
142: return prop;
143: }
144:
145: private Property addRecipeQueryProperty(String name, String dflt) {
146: Property prop = addProperty(new RecipeQueryProperty(this , name,
147: dflt));
148: prop.setPropertyClass(String.class);
149: return prop;
150: }
151:
152: private Property addPriorityProperty(String name, String dflt) {
153: Property prop = addProperty(new PriorityProperty(this , name,
154: dflt));
155: prop.setPropertyClass(String.class);
156: return prop;
157: }
158:
159: private void updatePropCount(Integer newCount) {
160: int count = newCount.intValue();
161:
162: if (count < 0)
163: count = 0;
164:
165: if (variableProps != null && count == variableProps.length)
166: return;
167: if (variableProps == null || variableProps.length == 0)
168: variableProps = null;
169:
170: // If the user reduced the desired number
171: if (variableProps != null && count < variableProps.length) {
172: if (log.isDebugEnabled())
173: log.debug("removing extra properties: "
174: + (variableProps.length - count));
175: // First, remove all the excess properties
176: for (int i = variableProps.length; i > count; i--) {
177: removeProperty(variableProps[i - 1]);
178: }
179:
180: // If they set the number to 0, we're done
181: if (count == 0) {
182: variableProps = null;
183: return;
184: }
185:
186: // Otherwise, copy the properties into a new, smaller array
187: Property[] newVariableProps = new Property[count];
188: System.arraycopy(variableProps, 0, newVariableProps, 0,
189: count);
190: variableProps = newVariableProps;
191: return;
192: } else if (variableProps != null
193: && count > variableProps.length) {
194: // User is adding properties
195: if (log.isDebugEnabled())
196: log.debug("adding additional properties "
197: + (count - variableProps.length));
198: // Move old ones to the bigger array
199: Property[] newVariableProps = new Property[count];
200: System.arraycopy(variableProps, 0, newVariableProps, 0,
201: variableProps.length);
202: // Then create the new ones
203: for (int i = variableProps.length; i < count; i++) {
204: newVariableProps[i] = addProperty("Value " + (i + 1),
205: "");
206: ((Property) newVariableProps[i])
207: .setToolTip("Value for Argument " + (i + 1));
208: }
209: variableProps = newVariableProps;
210: return;
211: } else {
212: // Didnt have any before - create all new from scratch
213: if (log.isDebugEnabled())
214: log.debug("Had no variableProps. Adding " + count);
215: variableProps = new Property[count];
216:
217: // Note: If you feel you want to change the name of these
218: // properties, see the "Hack Note" above.
219: for (int i = 0; i < count; i++) {
220: variableProps[i] = addProperty("Value " + (i + 1), "");
221: ((Property) variableProps[i])
222: .setToolTip("Value for Argument " + (i + 1));
223: }
224: }
225: }
226:
227: public ComponentData modifyComponentData(ComponentData data,
228: PopulateDb pdb) {
229: try {
230: Set targets = pdb.executeQuery(propTargetComponentQuery
231: .getValue().toString());
232: modifyComponentData(data, pdb, targets);
233: } catch (SQLException sqle) {
234: if (log.isErrorEnabled()) {
235: log.error("Exception", sqle);
236: }
237: }
238: return data;
239: }
240:
241: private void modifyComponentData(ComponentData data,
242: final PopulateDb pdb, final Set targets)
243: throws SQLException {
244: if (targets.contains(pdb.getComponentAlibId(data))) {
245: // do insertion
246: GenericComponentData comp = new GenericComponentData();
247: comp.setName(propName.getValue().toString());
248: comp.setPriority(propPriority.getValue().toString());
249: // FIXME: Do an equals with the ComponentData constants here?
250: String type = propType.getValue().toString();
251: if (type == null) {
252: if (log.isWarnEnabled()) {
253: log.warn("Null type for component " + comp);
254: }
255: comp.setType(null); // FIXME!
256: } else if (type.equals(ComponentData.PLUGIN))
257: comp.setType(ComponentData.PLUGIN);
258: else if (type.equals(ComponentData.AGENTBINDER))
259: comp.setType(ComponentData.AGENTBINDER);
260: else if (type.equals(ComponentData.NODEBINDER))
261: comp.setType(ComponentData.NODEBINDER);
262: else
263: comp.setType(type);
264: comp.setClassName(propClass.getValue().toString());
265:
266: // Add args.
267: if (variableProps != null) {
268: for (int i = 0; i < variableProps.length; i++) {
269: comp.addParameter(((Property) variableProps[i])
270: .getValue().toString());
271: }
272: }
273: comp.setParent(data);
274: comp.setOwner(this );
275:
276: // Reset the name to ensure uniqueness. This will use the user-specified name if possible,
277: // but tack on the first parameter and/or a number if necessary to ensure a unique name
278:
279: if (GenericComponentData.alreadyAdded(data, comp)) {
280: if (log.isDebugEnabled()) {
281: log.debug("Not re-adding component. "
282: + data.getName() + " already contains "
283: + comp);
284: }
285: } else {
286: comp.setName(GenericComponentData
287: .getSubComponentUniqueName(data, comp));
288:
289: data.addChildDefaultLoc(comp);
290: if (log.isInfoEnabled()) {
291: log.info("Inserted " + comp + " into "
292: + data.getName());
293: }
294: }
295: }
296: if (data.childCount() > 0) {
297: // for each child, call this same method.
298: ComponentData[] children = data.getChildren();
299: for (int i = 0; i < children.length; i++) {
300: modifyComponentData(children[i], pdb, targets);
301: }
302: }
303: }
304: }
|