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.agent.SimpleAgent;
029: import org.cougaar.tools.csmart.core.cdata.AgentAssetData;
030: import org.cougaar.tools.csmart.core.cdata.AgentComponentData;
031: import org.cougaar.tools.csmart.core.cdata.ComponentData;
032: import org.cougaar.tools.csmart.core.cdata.GenericComponentData;
033: import org.cougaar.tools.csmart.core.db.PDbBase;
034: import org.cougaar.tools.csmart.core.db.PopulateDb;
035: import org.cougaar.tools.csmart.core.property.BaseComponent;
036: import org.cougaar.tools.csmart.core.property.ConfigurableComponent;
037: import org.cougaar.tools.csmart.core.property.ModifiableComponent;
038: import org.cougaar.tools.csmart.core.property.Property;
039: import org.cougaar.tools.csmart.society.AgentComponent;
040: import org.cougaar.tools.csmart.society.ComponentBase;
041: import org.cougaar.tools.csmart.society.PropGroupComponent;
042: import org.cougaar.tools.csmart.society.RelationshipComponent;
043: import org.cougaar.util.log.Logger;
044:
045: import java.io.IOException;
046: import java.io.Serializable;
047: import java.net.URL;
048: import java.sql.SQLException;
049: import java.util.Collection;
050: import java.util.HashMap;
051: import java.util.Iterator;
052: import java.util.Map;
053: import java.util.Set;
054:
055: /**
056: * Recipe to add a complete Agent to the society. This agent
057: * consists of all required plugins relationships and asset data.
058: */
059: public class ComponentCollectionRecipe extends ComplexRecipeBase
060: implements Serializable {
061: protected static final String DESCRIPTION_RESOURCE_NAME = "collection-recipe-description.html";
062:
063: private Property propTargetComponent;
064:
065: /**
066: * Creates a new <code>ComponentCollectionRecipe</code> instance.
067: *
068: */
069: public ComponentCollectionRecipe() {
070: this ("Component Recipe");
071: }
072:
073: /**
074: * Creates a new <code>ComponentCollectionRecipe</code> instance.
075: *
076: * @param name Name of the Component
077: */
078: public ComponentCollectionRecipe(String name) {
079: super (name);
080: }
081:
082: public ComponentCollectionRecipe(String name, String assemblyId) {
083: super (name, assemblyId);
084: }
085:
086: public ComponentCollectionRecipe(String name, String assemblyId,
087: String recipeId) {
088: super (name, assemblyId, recipeId);
089: }
090:
091: public ComponentCollectionRecipe(String name, String assemblyId,
092: String recipeId, String initName) {
093: super (name, assemblyId, recipeId, initName);
094: }
095:
096: public ComponentCollectionRecipe(ComponentData cdata,
097: String assemblyId) {
098: super (cdata, assemblyId);
099: }
100:
101: // Do a normal setName, not silently changing just the recipe name,
102: // cause the free-floating components must have their names changed as well
103: public void setName(String newName) {
104: if (newName == null || newName.equals("")
105: || newName.equals(getRecipeName()))
106: return;
107:
108: super .setName(newName);
109:
110: // Must mark this recipe modified, cause the sub-component names have changed
111: // and must be changed in DB to restore correctly
112: // This is bug 2040
113: fireModification();
114: }
115:
116: /**
117: * Create the local Parent target query, then call the parent to complete.
118: */
119: public void initProperties() {
120: propTargetComponent = addRecipeQueryProperty(
121: PROP_TARGET_COMPONENT_QUERY,
122: PROP_TARGET_COMPONENT_QUERY_DFLT);
123: propTargetComponent
124: .setToolTip(PROP_TARGET_COMPONENT_QUERY_DESC);
125:
126: super .initProperties();
127:
128: // The super will set the parent target query
129:
130: // FIXME: Super also deals with this modification stuff
131: // And it says that a copy (init from CDATA) is modified
132: // modified = false;
133: // fireModification(new ModificationEvent(this, RECIPE_SAVED));
134:
135: }
136:
137: /**
138: * Gets the name of the html help file for this component.
139: *
140: * @return an <code>URL</code> value
141: */
142: public URL getDescription() {
143: return getClass().getResource(DESCRIPTION_RESOURCE_NAME);
144: }
145:
146: /**
147: * Adds any new data to the global <code>ComponentData</code> tree.
148: * No existing data is modified in this method.
149: * Warning: Assumes it is handed a ComponentData which contains
150: * all Agents below it.
151: *
152: * @param data Pointer to the Global <code>ComponentData</code> tree
153: * @return an updated <code>ComponentData</code> value
154: */
155: public ComponentData addComponentData(ComponentData data) {
156: ComponentData[] children = data.getChildren();
157: if (children == null)
158: return data;
159: for (int i = 0; i < children.length; i++) {
160: ComponentData child = children[i];
161: // for each child component data, if it's an agent's component data
162: if (child.getType() == ComponentData.AGENT) {
163: // get all my agent components
164: Iterator iter = ((Collection) getDescendentsOfClass(AgentComponent.class))
165: .iterator();
166: while (iter.hasNext()) {
167: AgentComponent agent = (AgentComponent) iter.next();
168: // Do not process Recipe Agents here, only in modify.
169: if (!child.getName().equals(RECIPE_AGENT)) {
170: // if the component data name matches the agent name
171: if (child.getName().equals(
172: agent.getShortName().toString())) {
173: // then set me as the owner of the component data
174: child.setOwner(this );
175:
176: if (log.isDebugEnabled())
177: log
178: .debug("addCData about to call it on agent "
179: + child.getName());
180: // and add the component data
181: agent.addComponentData(child);
182: }
183: }
184: }
185: } else if (child.getType() == ComponentData.SOCIETY
186: || child.getType() == ComponentData.HOST
187: || child.getType() == ComponentData.RECIPE
188: || child.getType() == ComponentData.NODE) {
189: // some container -- recurse down
190: addComponentData(child);
191: } else {
192: // get all top level Components
193: Iterator iter = ((Collection) getDescendentsOfClass(BaseComponent.class))
194: .iterator();
195: while (iter.hasNext()) {
196: BaseComponent comp = (BaseComponent) iter.next();
197: // if the component data name matches the agent name
198: if (child.getName().equals(
199: comp.getShortName().toString())) {
200: // then set me as the owner of the component data
201: child.setOwner(this );
202: // and add the component data
203: comp.addComponentData(child);
204: }
205: }
206: }
207:
208: }
209:
210: return data;
211: }
212:
213: /**
214: * Modifies the global <code>ComponentData</code> tree.
215: * This method is free to make any modifications it needs
216: * to the global tree, not just to it's own Component.
217: * <br>
218: * Currently, this component makes no modifications.
219: *
220: * @param data Pointer to the global <code>ComponentData</code>
221: * @param pdb Access to the database via <code>PopulateDb</code> object
222: * @return a modified <code>ComponentData</code> value
223: */
224: public ComponentData modifyComponentData(ComponentData data,
225: PopulateDb pdb) {
226: try {
227: Set dfltSet = pdb.executeQuery(getProperty(
228: PROP_TARGET_COMPONENT_QUERY).getValue().toString());
229: for (int i = 0; i < getChildCount(); i++) {
230: ConfigurableComponent cc = (ConfigurableComponent) getChild(i);
231: if (cc.getProperty(PROP_TARGET_COMPONENT_QUERY) == null) {
232: modifyComponentData(data, pdb, dfltSet, cc);
233: } else {
234: try {
235: Set targets = pdb.executeQuery(cc.getProperty(
236: PROP_TARGET_COMPONENT_QUERY).getValue()
237: .toString());
238: modifyComponentData(data, pdb, targets, cc);
239: } catch (SQLException sqle) {
240: if (log.isErrorEnabled()) {
241: log.error(
242: "Caught Exception executing query",
243: sqle);
244: }
245: return data;
246: }
247: }
248: }
249: } catch (SQLException sqle) {
250: if (log.isErrorEnabled()) {
251: log.error("Caught Exception executing query", sqle);
252: }
253: return data;
254: }
255:
256: return data;
257: }
258:
259: private void modifyComponentData(ComponentData data,
260: final PopulateDb pdb, final Set targets,
261: ConfigurableComponent cc) throws SQLException {
262: if (targets.contains(pdb.getComponentAlibId(data))) {
263: data = cc.modifyComponentData(data);
264: }
265: if (data.childCount() > 0) {
266: // for each child, call this same method.
267: ComponentData[] children = data.getChildren();
268: for (int i = 0; i < children.length; i++) {
269: modifyComponentData(children[i], pdb, targets, cc);
270: }
271: }
272: }
273:
274: public ComponentData getComponentData() {
275: ComponentData cd = new GenericComponentData();
276: cd.setType(ComponentData.RECIPE);
277: cd.setClassName(RECIPE_CLASS);
278: cd.setName(getRecipeName());
279: cd.setOwner(null);
280: cd.setParent(null);
281:
282: for (int i = 0; i < getChildCount(); i++) {
283: ConfigurableComponent cc = (ConfigurableComponent) getChild(i);
284: if (cc instanceof AgentComponent) {
285: AgentComponentData ac = new AgentComponentData();
286: ac.setName(cc.getShortName());
287: ac.setClassName(SimpleAgent.class.getName());
288: ac.addParameter(cc.getShortName().toString()); // Agents have one parameter, the agent name
289: ac.setOwner(cc);
290: ac.setParent(cd);
291: // // Add any new Parameters...
292: // Iterator iter = cc.getLocalProperties();
293: // while(iter.hasNext()) {
294: // Property p = (Property)iter.next();
295: // if (p != null)
296: // ac.addParameter(p.getValue().toString());
297: // }
298:
299: cd.addChild(cc.addComponentData(ac));
300:
301: } else if (cc instanceof ComponentBase) {
302: cd = cc.addComponentData(cd);
303: } else if (cc instanceof PropGroupComponent) {
304: // Need to create a dummy Agent as a container.
305: AgentComponentData ac = new AgentComponentData();
306: ac.setName(RECIPE_AGENT);
307: ac.setClassName(RECIPE_CLASS);
308: ac.setParent(cd);
309: AgentAssetData assetData = new AgentAssetData(null);
310: assetData.addPropertyGroup(((PropGroupComponent) cc)
311: .getPropGroupData());
312: ac.addAgentAssetData(assetData);
313: cd.addChild((ComponentData) ac);
314: } else if (cc instanceof RelationshipComponent) {
315: System.out.println("Have a RelationshipComponent");
316: }
317:
318: }
319:
320: return cd;
321: }
322:
323: public ModifiableComponent copy(String name) {
324: ComponentData cdata = getComponentData();
325: cdata.setName(name);
326:
327: // if (log.isDebugEnabled()) {
328: // log.debug(this + " produced CDATA: " + cdata);
329: // // Maybe look here to see if that param got added OK?
330: // ComponentData[] kids = cdata.getChildren();
331: // for (int i = 0; i < cdata.childCount(); i++) {
332: // int params = kids[i].parameterCount();
333: // log.debug("cdata.children["+i+"] has params: ");
334: // for (int j = 0; j < params; j++)
335: // log.debug("param["+j+"]= " + kids[i].getParameter(j));
336: // }
337: // }
338:
339: RecipeComponent component = new ComponentCollectionRecipe(
340: cdata, null);
341: component.initProperties();
342:
343: // FIXME: This next line means if the original was not modified
344: // then the copy will not be modified, even though the copy
345: // will not be in the DB (no RCP assembly)
346: // ((ComponentCollectionRecipe)component).modified = this.modified;
347: ((ComponentCollectionRecipe) component).oldAssemblyId = getAssemblyId();
348:
349: for (int i = 0; i < getChildCount(); i++) {
350: ConfigurableComponent child = (ConfigurableComponent) getChild(i);
351: Property prop = child
352: .getProperty(PROP_TARGET_COMPONENT_QUERY);
353: if (prop != null) {
354: String cname = child.getFullName().get(0).toString();
355: for (int j = 0; j < component.getChildCount(); j++) {
356: ConfigurableComponent newChild = (ConfigurableComponent) component
357: .getChild(j);
358: if (newChild.getShortName().equals(
359: child.getShortName())
360: || newChild
361: .getShortName()
362: .equals(
363: cname
364: + "|"
365: + ((ComponentBase) child)
366: .getComponentClassName()))
367: newChild.addProperty(prop.getName().last()
368: .toString(), prop.getValue());
369: }
370: }
371: }
372:
373: return component;
374: }
375:
376: public boolean saveToDatabase() {
377:
378: // The only way to preserve the target overrides in the children is to make them
379: // arguments of the parent, save, and then remove them from the parent.
380:
381: Map targets = new HashMap();
382: for (int i = 0; i < getChildCount(); i++) {
383: // ComponentBase child = (ComponentBase)getChild(i);
384: ConfigurableComponent child = (ConfigurableComponent) getChild(i);
385: if (child.getProperty(PROP_TARGET_COMPONENT_QUERY) != null) {
386: targets.put(("$$CP="
387: + ((ComponentBase) child)
388: .getComponentClassName() + "-" + i),
389: child.getProperty(PROP_TARGET_COMPONENT_QUERY)
390: .getValue());
391: }
392: }
393:
394: boolean retVal = super .saveToDatabase();
395:
396: try {
397: PDbBase.saveTargetOverrides(this , targets);
398: } catch (SQLException sqle) {
399: if (log.isErrorEnabled()) {
400: log.error("Error saving target overrides to database",
401: sqle);
402: }
403: retVal = false;
404: } catch (IOException ioe) {
405: if (log.isErrorEnabled()) {
406: log.error("Error saving target overrides to database",
407: ioe);
408: }
409: retVal = false;
410: }
411:
412: return retVal;
413: }
414:
415: }
|