0001: /*
0002: * <copyright>
0003: *
0004: * Copyright 2003-2004 BBNT Solutions, LLC
0005: * under sponsorship of the Defense Advanced Research Projects
0006: * Agency (DARPA).
0007: *
0008: * You can redistribute this software and/or modify it under the
0009: * terms of the Cougaar Open Source License as published on the
0010: * Cougaar Open Source Website (www.cougaar.org).
0011: *
0012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0023: *
0024: * </copyright>
0025: */
0026: package org.cougaar.tools.csmart.experiment;
0027:
0028: import org.cougaar.core.agent.SimpleAgent;
0029: import org.cougaar.core.node.Node;
0030: import org.cougaar.tools.csmart.core.cdata.AgentComponentData;
0031: import org.cougaar.tools.csmart.core.cdata.ComponentData;
0032: import org.cougaar.tools.csmart.core.cdata.GenericComponentData;
0033: import org.cougaar.tools.csmart.core.property.BaseComponent;
0034: import org.cougaar.tools.csmart.core.property.ConfigurableComponent;
0035: import org.cougaar.tools.csmart.core.property.ConfigurableComponentListener;
0036: import org.cougaar.tools.csmart.core.property.ModifiableComponent;
0037: import org.cougaar.tools.csmart.core.property.ModifiableConfigurableComponent;
0038: import org.cougaar.tools.csmart.core.property.ModificationEvent;
0039: import org.cougaar.tools.csmart.core.property.ModificationListener;
0040: import org.cougaar.tools.csmart.core.property.Property;
0041: import org.cougaar.tools.csmart.core.db.DBUtils;
0042: import org.cougaar.tools.csmart.core.db.DBConflictHandler;
0043: import org.cougaar.tools.csmart.recipe.RecipeBase;
0044: import org.cougaar.tools.csmart.recipe.RecipeComponent;
0045: import org.cougaar.tools.csmart.society.AgentBase;
0046: import org.cougaar.tools.csmart.society.AgentComponent;
0047: import org.cougaar.tools.csmart.society.SocietyBase;
0048: import org.cougaar.tools.csmart.society.SocietyComponent;
0049: import org.cougaar.tools.csmart.ui.viewer.CSMART;
0050: import org.cougaar.tools.csmart.util.ReadOnlyProperties;
0051: import org.cougaar.util.log.Logger;
0052:
0053: import javax.swing.*;
0054: import java.io.File;
0055: import java.io.IOException;
0056: import java.io.ObjectInputStream;
0057: import java.io.OutputStream;
0058: import java.net.URL;
0059: import java.util.*;
0060: import java.util.List;
0061: import java.awt.*;
0062:
0063: /**
0064: * org.cougaar.tools.csmart.experiment
0065: *
0066: */
0067: public abstract class ExperimentBase extends
0068: ModifiableConfigurableComponent implements Experiment {
0069: private static final String DESCRIPTION_RESOURCE_NAME = "description.html";
0070: // Member Variables
0071: private SocietyComponent societyComponent = null;
0072: private final List hosts = new ArrayList();
0073: private final List nodes = new ArrayList();
0074: final List recipes = new ArrayList();
0075: ReadOnlyProperties defaultNodeArguments;
0076: private File resultDirectory; // where to store results
0077: private transient boolean editInProgress = false;
0078: private transient boolean runInProgress = false;
0079: ComponentData completeSociety = null;
0080: private String expID = null; // An Experiment has a single ExpID
0081: private String trialID = null;
0082:
0083: // modification event
0084: private static final int EXPERIMENT_SAVED = 1;
0085: transient LeafOnlyConfigWriter configWriter = null;
0086: transient Logger log;
0087: // Mark whether the experiment has been modified
0088: // and should be saved
0089: boolean modified = true;
0090: // add an observer to my arguments
0091: // if these arguments are modified, then
0092: // notify listeners on the experiment that it's modified
0093: private transient Observer myObserver = null;
0094: /**
0095: * Create a modification listener, which is registered on
0096: * all the experiment components. If any components
0097: * are modified, then mark this experiment as modified,
0098: * and fire a modification event to the experiment's
0099: * modification listeners.
0100: * Checks for modification event being EXPERIMENT_SAVED
0101: * in which case, it does not mark the experiment modified.
0102: */
0103: private final ModificationListener myModificationListener = new MyModificationListener();
0104:
0105: // The assembly holding community info for this Experiment.
0106: private String commAsb = null;
0107:
0108: public ExperimentBase(String name) {
0109: super (name);
0110: }
0111:
0112: public ExperimentBase(String name, String expID, String trialID) {
0113: super (name);
0114: this .expID = expID;
0115: this .trialID = trialID;
0116: }
0117:
0118: final void createLogger() {
0119: log = CSMART.createLogger(this .getClass().getName());
0120: }
0121:
0122: final void createObserver() {
0123: if (myObserver == null) {
0124: myObserver = new Observer() {
0125: public void update(final Observable o, final Object arg) {
0126: fireModification();
0127: }
0128: };
0129: defaultNodeArguments.addObserver(myObserver);
0130: }
0131: }
0132:
0133: /**
0134: * Adds a <code>societyComponent</code> to this Experiment.
0135: *
0136: * @param sc
0137: * @exception java.lang.IllegalArgumentException if an error occurs
0138: */
0139: public final void addSocietyComponent(SocietyComponent sc)
0140: throws IllegalArgumentException {
0141: if (this .societyComponent == null) {
0142: setSocietyComponent(sc);
0143: } else {
0144: throw new IllegalArgumentException(
0145: "Already have a societyComponent in experiment "
0146: + this );
0147: }
0148: }
0149:
0150: /**
0151: * Removes the <code>SocietyComponent</code> from this experiment
0152: *
0153: */
0154: public final void removeSocietyComponent() {
0155: if (this .societyComponent == null)
0156: return;
0157: removeListeners((ModifiableConfigurableComponent) societyComponent);
0158: this .societyComponent = null;
0159: fireModification();
0160: }
0161:
0162: /**
0163: * Returns the total number of Societies in this experiment.
0164: * Since experiments can only have 1 society, this returns
0165: * a 0 or 1 value.
0166: *
0167: * @return an <code>int</code> value
0168: */
0169: public final int getSocietyComponentCount() {
0170: return (this .societyComponent == null ? 0 : 1);
0171: }
0172:
0173: /**
0174: * Return the <code>SocietyComponent</code>
0175: *
0176: * @return a <code>SocietyComponent</code> value
0177: */
0178: public final SocietyComponent getSocietyComponent() {
0179: return this .societyComponent;
0180: }
0181:
0182: final void setSocietyComponent(SocietyComponent society) {
0183: if (this .societyComponent != null)
0184: removeSocietyComponent();
0185: this .societyComponent = society;
0186: installListeners((ModifiableConfigurableComponent) society);
0187: fireModification();
0188: }
0189:
0190: private void installListeners(
0191: ModifiableConfigurableComponent component) {
0192: component.addModificationListener(myModificationListener);
0193: }
0194:
0195: private void removeListeners(
0196: ModifiableConfigurableComponent component) {
0197: component.removeModificationListener(myModificationListener);
0198: }
0199:
0200: /**
0201: * Adds an array of <code>RecipeComponent</code>s to this
0202: * experiment.
0203: *
0204: * @param newRecipes RecipeComponents
0205: */
0206: public final void setRecipeComponents(RecipeComponent[] newRecipes) {
0207: for (int i = 0; i < recipes.size(); i++)
0208: removeListeners((ModifiableConfigurableComponent) recipes
0209: .get(i));
0210: recipes.clear();
0211: // FIXME: Remove duplicates?
0212: for (int i = 0; i < newRecipes.length; i++)
0213: installListeners((ModifiableConfigurableComponent) newRecipes[i]);
0214: recipes.addAll(Arrays.asList(newRecipes));
0215: fireModification();
0216: }
0217:
0218: /**
0219: * Adds a <code>RecipeComponent</code> to this Experiment
0220: *
0221: * @param recipe - <code>RecipeComponent</code> to add to Experiment
0222: */
0223: public final void addRecipeComponent(RecipeComponent recipe)
0224: throws IllegalArgumentException {
0225: if (!recipes.contains(recipe)) {
0226: recipes.add(recipe);
0227: installListeners((ModifiableConfigurableComponent) recipe);
0228: fireModification();
0229: } else {
0230: throw new IllegalArgumentException(
0231: "Recipe already exists in experiment");
0232: }
0233: }
0234:
0235: /**
0236: * Removes the specified <code>RecipeComponent</code>.
0237: *
0238: * @param recipe
0239: */
0240: public final void removeRecipeComponent(RecipeComponent recipe) {
0241: if (!this .recipes.contains(recipe))
0242: return;
0243: this .recipes.remove(recipe);
0244: removeListeners((ModifiableConfigurableComponent) recipe);
0245: fireModification();
0246: }
0247:
0248: /**
0249: * Returns the total number of recipes in this experiment.
0250: *
0251: * @return an <code>int</code> value
0252: */
0253: public final int getRecipeComponentCount() {
0254: return this .recipes.size();
0255: }
0256:
0257: /**
0258: * Gets a specific recipe based on Index.
0259: *
0260: * @param i
0261: * @return a <code>RecipeComponent</code> value
0262: * @exception java.lang.IndexOutOfBoundsException if an error occurs
0263: */
0264: public final RecipeComponent getRecipeComponent(int i)
0265: throws IndexOutOfBoundsException {
0266: return (RecipeComponent) recipes.get(i);
0267: }
0268:
0269: /**
0270: * Gets all <code>RecipeComponents</code> for this experiment.
0271: *
0272: * @return a <code>RecipeComponent[]</code> value
0273: */
0274: public final RecipeComponent[] getRecipeComponents() {
0275: return (RecipeComponent[]) recipes
0276: .toArray(new RecipeComponent[recipes.size()]);
0277: }
0278:
0279: /**
0280: * Adds a new component to this experiment.
0281: * Currently only two Component Types are accepted:
0282: * <br><code>SocietyComponent</code>
0283: * <br><code>RecipeComponent</code>
0284: *
0285: * @param comp
0286: * @exception java.lang.IllegalArgumentException if an error occurs
0287: */
0288: public final void addComponent(final ModifiableComponent comp)
0289: throws IllegalArgumentException {
0290: if (comp instanceof SocietyComponent) {
0291: try {
0292: addSocietyComponent((SocietyComponent) comp);
0293: } catch (IllegalArgumentException e) {
0294: if (log.isErrorEnabled()) {
0295: log.error("SocietyComponent already set");
0296: }
0297: }
0298: } else if (comp instanceof RecipeComponent) {
0299: addRecipeComponent((RecipeComponent) comp);
0300: } else {
0301: throw new IllegalArgumentException(
0302: "Unsupported Component Type" + this );
0303: }
0304: }
0305:
0306: /**
0307: * Removes the given component from the Experiment.
0308: * If the component is not supported, an exception
0309: * is throw.
0310: *
0311: * @param comp
0312: * @exception java.lang.IllegalArgumentException if an error occurs
0313: */
0314: public final void removeComponent(ModifiableComponent comp)
0315: throws IllegalArgumentException {
0316: if (comp instanceof SocietyComponent) {
0317: removeSocietyComponent();
0318: } else if (comp instanceof RecipeComponent) {
0319: removeRecipeComponent((RecipeComponent) comp);
0320: } else {
0321: throw new IllegalArgumentException(
0322: "Unsupported Component Type");
0323: }
0324: }
0325:
0326: /**
0327: * Returns the total number of Components
0328: * (Recipe and Society) in this experiment.
0329: *
0330: * @return an <code>int</code> value
0331: */
0332: public final int getComponentCount() {
0333: return getSocietyComponentCount() + recipes.size();
0334: }
0335:
0336: /**
0337: * @return a <code>ModifiableConfigurableComponent[]</code> array of
0338: * all the components in the experiment
0339: */
0340: public final ModifiableComponent[] getComponentsAsArray() {
0341: List comps = getComponents();
0342: ModifiableComponent[] compArray = (ModifiableComponent[]) comps
0343: .toArray(new ModifiableComponent[comps.size()]);
0344: return compArray;
0345: }
0346:
0347: /**
0348: * Get all the recipes and the society.
0349: * @return List list of all the components in the experiment
0350: */
0351: public final List getComponents() {
0352: List comps = new ArrayList();
0353: for (int i = 0; i < getRecipeComponentCount(); i++) {
0354: comps.add(getRecipeComponent(i));
0355: }
0356: if (getSocietyComponent() != null)
0357: comps.add(getSocietyComponent());
0358: return comps;
0359: }
0360:
0361: /**
0362: * Set run in progress. Used by UI tools to indicate that an
0363: * experiment is being run. Note that this is distinct from
0364: * setting the runnability flag, which indicates whether the experiment
0365: * can ever be run.
0366: * @param newRunInProgress
0367: */
0368: public final void setRunInProgress(boolean newRunInProgress) {
0369: runInProgress = newRunInProgress;
0370: }
0371:
0372: /**
0373: * Return whether or not experiment is being run.
0374: * @return boolean whether or not experiment is being run
0375: */
0376: public final boolean isRunInProgress() {
0377: return runInProgress;
0378: }
0379:
0380: /**
0381: * Return whether or not experiment is runnable. An experiment is runnable:
0382: * if it has a host-node-agent mapping, and
0383: * it has no unbound properties, and
0384: * it's not being edited or run, and
0385: * it's been saved in the database (i.e. the modified flag is false)
0386: * @return whether or not an experiment is runnable
0387: */
0388: public final boolean isRunnable() {
0389: if (!hasConfiguration() || modified)
0390: return false;
0391: return !runInProgress; // allow user to run experiment they're editing
0392: }
0393:
0394: /**
0395: * Set edit in progress. Used by UI tools to indicate that an
0396: * experiment is being edited. Note that this is distinct from
0397: * setting the editability flag, which indicates whether the experiment
0398: * can ever be edited.
0399: * @param newEditInProgress
0400: */
0401: public final void setEditInProgress(boolean newEditInProgress) {
0402: editInProgress = newEditInProgress;
0403: }
0404:
0405: /**
0406: * Return whether or not experiment is being edited.
0407: * Note that the experiment may be viewed (but not edited) in an editor,
0408: * even if this flag is not set.
0409: * @return boolean whether or not experiment is being edited
0410: */
0411: public final boolean isEditInProgress() {
0412: return editInProgress;
0413: }
0414:
0415: /**
0416: * Stop after the current trial.
0417: * This invokes experimentStopped.
0418: */
0419: public final void stop() {
0420: // TODO: stop the experiment after the current trial
0421: experimentStopped();
0422: }
0423:
0424: /**
0425: * Notify listeners that experiment was terminated.
0426: */
0427: public final void experimentStopped() {
0428: // Tell the Societies in the experiment they are no longer running?
0429: if (societyComponent != null)
0430: societyComponent.setRunning(false);
0431: }
0432:
0433: /**
0434: * Returns the Default Node Arguments
0435: *
0436: * @return a <code>Properties</code> object containing all default Node Args.
0437: */
0438: public final Properties getDefaultNodeArguments() {
0439: return defaultNodeArguments;
0440: }
0441:
0442: public final File getResultDirectory() {
0443: return resultDirectory;
0444: }
0445:
0446: public final void setResultDirectory(File resultDirectory) {
0447: this .resultDirectory = resultDirectory;
0448: }
0449:
0450: /**
0451: * Returns the Name of this Experiment
0452: *
0453: * @return a <code>String</code> value
0454: */
0455: public final String getExperimentName() {
0456: return getShortName();
0457: }
0458:
0459: /**
0460: * Returns the name of this component
0461: *
0462: * @return a <code>String</code> value
0463: */
0464: public final String toString() {
0465: return this .getShortName();
0466: }
0467:
0468: /**
0469: * Get the URL of the file that describes this experiment.
0470: */
0471: public final URL getDescription() {
0472: return getClass().getResource(
0473: ExperimentBase.DESCRIPTION_RESOURCE_NAME);
0474: }
0475:
0476: public final void initProperties() {
0477: // put all the properties in here
0478: // the list of components are children
0479: // the editability & runability are properties
0480: // the hosts, trial, etc should all be properties
0481: // then we wouldn't need the special copy mechanism
0482: // (if all the sub-pieces were also components)
0483: }
0484:
0485: /**
0486: * If the experiment was saved, let the listeners know,
0487: * but don't mark our modified flag.
0488: * If the society or any recipe was changed, tell the listeners that the
0489: * experiment changed.
0490: * If the society or recipe was saved, ignore this,
0491: * as the experiment must still be saved.
0492: */
0493: private void notifyExperimentListeners(ModificationEvent e) {
0494: if (e.getWhatChanged() == ExperimentBase.EXPERIMENT_SAVED) {
0495: super .fireModification();
0496: return;
0497: }
0498: if (e.getWhatChanged() == SocietyBase.SOCIETY_SAVED
0499: || e.getWhatChanged() == RecipeBase.RECIPE_SAVED)
0500: return;
0501: // an experiment, society, or recipe was changed,
0502: // mark this experiment as modified, and notify the listeners
0503: fireModification();
0504: }
0505:
0506: public final void fireModification() {
0507: modified = true;
0508: super .fireModification();
0509: }
0510:
0511: private void addDefaultNodeArguments(ComponentData theSoc) {
0512: Properties props = getDefaultNodeArguments();
0513: for (Iterator i = props.entrySet().iterator(); i.hasNext();) {
0514: Map.Entry entry = (Map.Entry) i.next();
0515: String entVal = entry.getKey().toString();
0516: if (entVal.startsWith("-X")) {
0517: if (entry.getValue().equals("")
0518: || entry.getValue() == null) {
0519: theSoc.addParameter(entry.getKey());
0520: } else {
0521: theSoc.addParameter(entry.getKey() + "="
0522: + entry.getValue());
0523: }
0524: } else if (entVal.startsWith("X:")) {
0525: theSoc.addParameter("-X" + entry.getKey() + "="
0526: + entry.getValue());
0527: } else {
0528: theSoc.addParameter("-D" + entry.getKey() + "="
0529: + entry.getValue());
0530: }
0531: }
0532: }
0533:
0534: private void readObject(ObjectInputStream ois) throws IOException,
0535: ClassNotFoundException {
0536: ois.defaultReadObject();
0537: boolean temp = modified;
0538: createLogger();
0539: createObserver();
0540: modified = temp;
0541: editInProgress = false;
0542: runInProgress = false;
0543: }
0544:
0545: // Put a bunch of Prop$ as parameters to the given component.
0546: // even if the component itself doesnt think it wants it.
0547: // This may cause problems for Agents, I think....
0548: private void addPropertiesAsParameters(ComponentData cd,
0549: BaseComponent cp) {
0550: for (Iterator it = cp.getProperties(); it.hasNext();) {
0551: Property prop = (Property) it.next();
0552: if (prop != null) {
0553: Object pvalue = prop.getValue();
0554: if (pvalue instanceof String)
0555: // FIXME: by doing getName.last(), it flattens out any
0556: // internal hierarchy. Surely that makes
0557: // it impossible for these to be much use?
0558: // FIXME??
0559: cd.addParameter(PROP_PREFIX + prop.getName().last()
0560: + "=" + pvalue);
0561: }
0562: }
0563: }
0564:
0565: /**
0566: * Adds the Given Host to the Experiment
0567: * If the given host already exists, an exception is thrown.
0568: *
0569: * @param name - Name of the new Host
0570: * @return a <code>HostComponent</code> for this host.
0571: * @exception java.lang.IllegalArgumentException if an error occurs
0572: */
0573: public final HostComponent addHost(String name)
0574: throws IllegalArgumentException {
0575: // FIXME: Maybe forbid localhost?
0576: if (hostExists(name)) {
0577: throw new IllegalArgumentException(
0578: "Host Already Exists in Society");
0579: } else {
0580: ExperimentHost eh = new ExperimentHost(name);
0581: eh.initProperties();
0582: return addHostComponent(eh);
0583: }
0584: }
0585:
0586: /**
0587: * Get the Hosts in this experiment.
0588: * As a side effect, reconcile the Node/Agent mapping, if the experiment
0589: * is marked as modified.
0590: **/
0591: public final HostComponent[] getHostComponents() {
0592: if (modified) {
0593: reconcileNodeAgentMapping();
0594: }
0595: return (HostComponent[]) hosts.toArray(new HostComponent[hosts
0596: .size()]);
0597: }
0598:
0599: public final HostComponent[] getHostComponentsNoReconcile() {
0600: return (HostComponent[]) hosts.toArray(new HostComponent[hosts
0601: .size()]);
0602: }
0603:
0604: /**
0605: * Removes the given host from the experiment.
0606: *
0607: * @param hostComponent - <code>HostComponent</code> to remove.
0608: */
0609: public final void removeHost(HostComponent hostComponent) {
0610: if (!hosts.contains(hostComponent))
0611: return;
0612: hosts.remove(hostComponent);
0613: // Let the host disassociate itself from nodes
0614: ((ExperimentHost) hostComponent).dispose();
0615: removeListeners((ExperimentHost) hostComponent);
0616: fireModification();
0617: }
0618:
0619: /**
0620: * Renames a host in the Experiment.
0621: * If a host with the given name already exists, an exception
0622: * is thrown.
0623: *
0624: * @param hostComponent - <code>HostComponent</code> of the host to be renamed.
0625: * @param name - New Host Name
0626: * @exception java.lang.IllegalArgumentException if an error occurs
0627: */
0628: public final void renameHost(HostComponent hostComponent,
0629: String name) throws IllegalArgumentException {
0630: // Fixme: Maybe forbid localhost?
0631: ExperimentHost testHost = new ExperimentHost(name);
0632: if (hosts.contains(testHost)) {
0633: throw new IllegalArgumentException(
0634: "Host Already Exists in Society");
0635: } else {
0636: if (hostComponent.getFullName().equals(name))
0637: return;
0638: hosts.remove(hostComponent);
0639: hostComponent.setName(name);
0640: hosts.add(hostComponent);
0641: fireModification();
0642: }
0643: }
0644:
0645: /**
0646: * Insure that we have a valid nameserver specification. There are
0647: * several possibilities: If the default node nameserver argument
0648: * has been set, try to make that be the name server. Parse out the
0649: * host name part. Then scan all the hosts that have nodes
0650: * and check to see if any host matches that specified by the
0651: * default node nameserver argument. If it does, keep that
0652: * nameserver. If it doesn't (or if there was no default node
0653: * nameserver argument) then use the first host as the nameserver.
0654: **/
0655: public final void updateNameServerHostName() {
0656: Properties defaultNodeArgs = getDefaultNodeArguments();
0657: String oldNameServer = defaultNodeArgs
0658: .getProperty(Experiment.NAME_SERVER);
0659: String newNameServer = null;
0660: String dfltNameServer = null;
0661: String nameServerHost = null;
0662: if (oldNameServer != null) {
0663: dfltNameServer = oldNameServer;
0664: int colon = oldNameServer.indexOf(':');
0665: if (colon >= 0) {
0666: nameServerHost = oldNameServer.substring(0, colon);
0667: } else {
0668: nameServerHost = oldNameServer;
0669: }
0670: }
0671:
0672: // This does the NodeAgent reconcilation, if the experiment is modified
0673: HostComponent[] hosts = getHostComponents();
0674:
0675: hostLoop: for (int i = 0; i < hosts.length; i++) {
0676: NodeComponent[] nodes = hosts[i].getNodes();
0677: if (nodes.length == 0)
0678: continue;
0679: String this Host = hosts[i].getShortName();
0680: if (this Host.equals(nameServerHost)) {
0681: newNameServer = oldNameServer;
0682: break hostLoop; // Use existing nameserver definition
0683: }
0684: if (dfltNameServer == null) { // First host is default
0685: dfltNameServer = this Host + ":"
0686: + Experiment.NAME_SERVER_PORTS;
0687: if (oldNameServer == null) {
0688: break hostLoop; // Use dfltNameServer
0689: }
0690: }
0691: }
0692: if (newNameServer == null)
0693: newNameServer = dfltNameServer;
0694:
0695: // set new server in all nodes
0696: // Do not, again, reconcile NodeAgent mapping
0697: // This method doesnt care, and if the experiment is modified, getHostComponents
0698: // above already does it
0699: NodeComponent[] nodes = getNodesInner(false);
0700: for (int i = 0; i < nodes.length; i++) {
0701: NodeComponent node = nodes[i];
0702: Properties arguments = node.getArguments();
0703: // Insure no per-node override exists
0704: arguments.remove(Experiment.NAME_SERVER);
0705: }
0706: // Now install experiment-wide setting.
0707: if (newNameServer != null) {
0708: defaultNodeArgs.setProperty(Experiment.NAME_SERVER,
0709: newNameServer);
0710: }
0711: }
0712:
0713: private boolean hostExists(String name) {
0714: return (hosts.contains(new ExperimentHost(name))) ? true
0715: : false;
0716: }
0717:
0718: private ExperimentHost addHostComponent(ExperimentHost host) {
0719: if (hosts.contains(host))
0720: return host;
0721: hosts.add(host);
0722: installListeners(host);
0723: fireModification();
0724: return host;
0725: }
0726:
0727: /**
0728: * Adds a new node to this experiment. If the node
0729: * currently exists, an exception is thrown.
0730: *
0731: * @param name - Name of new Node
0732: * @return a <code>NodeComponent</code> value
0733: * @exception java.lang.IllegalArgumentException if an error occurs
0734: */
0735: public final NodeComponent addNode(String name)
0736: throws IllegalArgumentException {
0737: // if have an agent of this name, complain
0738: if (!agentNameUnique(name)) {
0739: throw new IllegalArgumentException(
0740: "Name already in use (by a Node or Agent)");
0741: } else if (!nodeExists(name)) {
0742: ExperimentNode result = new ExperimentNode(name, this );
0743: result.initProperties();
0744: addNodeComponent(result);
0745: return result;
0746: } else {
0747: throw new IllegalArgumentException("Node already exists");
0748: }
0749: }
0750:
0751: /**
0752: * Removes the specified node from the Experiment
0753: *
0754: * @param nc <code>NodeComponent</code> of the Node to remove
0755: */
0756: public final void removeNode(NodeComponent nc) {
0757: if (!nodes.contains(nc))
0758: return;
0759: ExperimentNode expNode = (ExperimentNode) nc;
0760: nodes.remove(nc);
0761: expNode.dispose(); // Let the node disassociate itself from agents
0762: removeListeners(expNode);
0763: fireModification();
0764: }
0765:
0766: /**
0767: * Renames a currently existing Node in this Experiment.
0768: * If a node with the new name already exists, an exception is thrown
0769: *
0770: * @param nc - Node Component of the Node to change name
0771: * @param name - New Name
0772: * @exception java.lang.IllegalArgumentException if an error occurs
0773: */
0774: public final void renameNode(NodeComponent nc, String name)
0775: throws IllegalArgumentException {
0776: if (nodeExists(name)) {
0777: throw new IllegalArgumentException(
0778: "Node name already exists!");
0779: } else if (!agentNameUnique(name)) {
0780: throw new IllegalArgumentException("Name already in use");
0781: } else {
0782: if (nc.getFullName().equals(name))
0783: return;
0784: nodes.remove(nc);
0785: nc.setName(name);
0786: nodes.add(nc);
0787: fireModification();
0788: }
0789: }
0790:
0791: /**
0792: * Get the Nodes in this Experiment.
0793: * As a side-effect, ensure that the NameServer Host property
0794: * is set correctly, and ensure that the Node/Agent mapping
0795: * is up-to-date.
0796: */
0797: public final NodeComponent[] getNodeComponents() {
0798: // Note that as a side-effect, this will also
0799: // reconcile the node/agent mapping, if the experiment is modified
0800: updateNameServerHostName(); // Be sure this is update-to-date
0801:
0802: // Since we just did the reconciliation if the experiment is modified,
0803: // only do it here if the experiment is _not_ modified
0804: // -- I know, shouldnt need to, but this preserves current functionality closer
0805: return getNodesInner(!isModified());
0806: }
0807:
0808: private boolean nodeExists(String name) {
0809: return (nodes.contains(new ExperimentNode(name, this ))) ? true
0810: : false;
0811: }
0812:
0813: public final boolean agentNameUnique(String name) {
0814: if (name == null || name.equals(""))
0815: return false;
0816:
0817: // is this agent / node name combination unique
0818: for (Iterator i = nodes.iterator(); i.hasNext();) {
0819: NodeComponent nc = (NodeComponent) i.next();
0820: if (nc.getShortName().equals(name))
0821: return false;
0822: }
0823: for (Iterator i = getAgentsList().iterator(); i.hasNext();) {
0824: AgentComponent nc = (AgentComponent) i.next();
0825: if (nc.getShortName().equals(name))
0826: return false;
0827: }
0828: return true;
0829: }
0830:
0831: final void addNodeComponent(ExperimentNode node) {
0832: if (nodes.contains(node))
0833: return;
0834: nodes.add(node);
0835: installListeners(node);
0836: fireModification();
0837: }
0838:
0839: private NodeComponent[] getNodesInner(boolean check) {
0840: // if (log.isDebugEnabled())
0841: // log.debug("getNodesInner(" + check + ")");
0842:
0843: if (check)
0844: reconcileNodeAgentMapping();
0845:
0846: return (NodeComponent[]) nodes.toArray(new NodeComponent[nodes
0847: .size()]);
0848: }
0849:
0850: // Ensure only Agents in the Experiment are assigned
0851: // to Nodes, and that all Agents assigned to Nodes are the objects
0852: // given by the society & recipes
0853: // Note that this takes a little time
0854: private void reconcileNodeAgentMapping() {
0855: // if (log.isDebugEnabled())
0856: // log.debug("reconcileNodeAgentMapping", new Throwable());
0857: if (log.isDebugEnabled())
0858: log.debug("reconcileNodeAgentMapping");
0859:
0860: List agents = getAgentsList();
0861: if (nodes == null)
0862: return;
0863: for (Iterator i = nodes.iterator(); i.hasNext();) {
0864: NodeComponent nc = (NodeComponent) i.next();
0865: AgentComponent[] nodeAgent = nc.getAgents();
0866: for (int j = 0; j < nodeAgent.length; j++) {
0867: int index = agents.indexOf(nodeAgent[j]);
0868: if (index < 0) {
0869: // if (!agents.contains(nodeAgent[j]))
0870: nc.removeAgent(nodeAgent[j]);
0871: } else {
0872: // Find the agent in the agents list which is .equals
0873:
0874: // We're never going to find a second Agent with this
0875: // name on a Node. So no need to keep it in the list
0876: // of Agents in the Experiment we compare against
0877:
0878: AgentComponent ag = (AgentComponent) agents
0879: .remove(index);
0880: // if its not ==, remove it from the Node, and re-add it
0881: // to ensure only the correct object in use
0882: if (ag != null && ag != nodeAgent[j]) {
0883: nc.removeAgent(nodeAgent[j]);
0884: nc.addAgent(ag);
0885: }
0886: }
0887: }
0888: }
0889: }
0890:
0891: // returns a collection of all agents written.
0892: private Collection generateNodeComponent(NodeComponent node,
0893: ComponentData parent) {
0894: Set writtenAgents = new HashSet();
0895:
0896: ComponentData nc = new GenericComponentData();
0897: nc.setType(ComponentData.NODE);
0898: nc.setName(node.getShortName());
0899: nc.setClassName(Node.class.getName()); // leave this out?? FIXME
0900: nc.setOwner(this ); // the experiment? FIXME
0901: nc.setParent(parent);
0902: // ComponentName name =
0903: // new ComponentName((ConfigurableComponent) node, "ConfigurationFileName");
0904: nc.addParameter(node.getShortName());
0905: Properties props = node.getArguments();
0906: for (Iterator i = props.entrySet().iterator(); i.hasNext();) {
0907: Map.Entry entry = (Map.Entry) i.next();
0908: String entVal = entry.getKey().toString();
0909: if (entVal.startsWith("-X")) {
0910: if (entry.getValue().equals("")
0911: || entry.getValue() == null) {
0912: nc.addParameter(entry.getKey());
0913: } else {
0914: nc.addParameter(entry.getKey() + "="
0915: + entry.getValue());
0916: }
0917: } else if (entVal.startsWith("X:")) {
0918: nc.addParameter("-X" + entry.getKey() + "="
0919: + entry.getValue());
0920: } else {
0921: nc.addParameter("-D" + entry.getKey() + "="
0922: + entry.getValue());
0923: }
0924:
0925: // nc.addParameter("-D" + entry.getKey() + "=" + entry.getValue());
0926: }
0927: addPropertiesAsParameters(nc, node);
0928: if (log.isDebugEnabled()) {
0929: log.debug("Adding: " + nc.getName() + " to "
0930: + parent.getName());
0931: }
0932: parent.addChild(nc);
0933:
0934: // Now get the Agents on this Node
0935: AgentComponent[] agents = node.getAgents();
0936: if (agents != null && agents.length > 0) {
0937: for (int j = 0; j < agents.length; j++) {
0938: generateAgentComponent(agents[j], nc, parent.getOwner());
0939: // if(log.isDebugEnabled()) {
0940: // log.debug("Remember Agent: " + agents[j].getFullName().toString());
0941: // }
0942: writtenAgents.add(agents[j]);
0943: }
0944: }
0945: return writtenAgents;
0946: }
0947:
0948: public final List getAgentsList() {
0949: List agents = getAgentsInSociety();
0950: if (agents == null)
0951: agents = new ArrayList();
0952: List other = getAgentsInRecipes();
0953: if (other != null && (!other.isEmpty()))
0954: agents.addAll(other);
0955: return agents;
0956: }
0957:
0958: public final AgentComponent[] getAgents() {
0959: List agents = getAgentsList();
0960: return (AgentComponent[]) agents
0961: .toArray(new AgentComponent[agents.size()]);
0962: }
0963:
0964: /**
0965: * Get the agents from the society in the experiment.
0966: */
0967: private List getAgentsInSociety() {
0968: List agents = new ArrayList();
0969: if (societyComponent != null) {
0970: AgentComponent[] sags = societyComponent.getAgents();
0971: if (sags != null && sags.length > 0)
0972: agents.addAll(Arrays.asList(sags));
0973: }
0974: return agents;
0975: }
0976:
0977: private List getAgentsInRecipes() {
0978: List agents = new ArrayList();
0979: for (int i = 0; i < recipes.size(); i++) {
0980: RecipeComponent recipe = (RecipeComponent) recipes.get(i);
0981: AgentComponent[] impagents = recipe.getAgents();
0982: if (impagents != null && impagents.length > 0)
0983: agents.addAll(Arrays.asList(impagents));
0984: }
0985: return agents;
0986: }
0987:
0988: private void generateAgentComponent(AgentComponent agent,
0989: ComponentData parent, ConfigurableComponent owner) {
0990: if (log.isDebugEnabled()) {
0991: log.debug("Adding Agent: " + agent.getFullName().toString()
0992: + " To " + parent.getName());
0993: }
0994:
0995: AgentComponentData ac = new AgentComponentData();
0996: ac.setName(agent.getShortName());
0997:
0998: // Change AgentComponent to have a getClass?
0999: if (agent instanceof AgentBase)
1000: ac.setClassName(((AgentBase) agent).getAgentClassName());
1001: else
1002: ac.setClassName(SimpleAgent.class.getName());
1003:
1004: ac.addParameter(agent.getShortName()); // Agents have one parameter, the agent name
1005: ac.setOwner(owner);
1006: ac.setParent(parent);
1007:
1008: // FIXME: This is the lines that forces all the $Prop things
1009: // on the agents to be stored!!!
1010: //addPropertiesAsParameters(ac, agent);
1011: parent.addChild(ac);
1012: }
1013:
1014: // Generate a host-node-agent ComponentData tree in the global
1015: // completeSociety variable
1016: // This saves all assignments of agents to Nodes, including
1017: // those nodes not assigned to Hosts.
1018: // It also gathers the command-line arguments
1019: final void generateHNACDATA() {
1020: Set savedNodes = new HashSet();
1021: Set savedAgents = new HashSet();
1022:
1023: // getNodeComponents calls getNodesInner which should
1024: // reconcile old Agents & new Agents
1025: updateNameServerHostName();
1026: // Force a reconciliation, once, even if the Experiment says it is not
1027: // modified -- just to be safe
1028: NodeComponent[] nodesToWrite = getNodesInner(!isModified());
1029: AgentComponent[] agentsToWrite = getAgents();
1030:
1031: if (log.isDebugEnabled())
1032: log.debug("genHNA has " + agentsToWrite.length
1033: + " Agents to write");
1034:
1035: completeSociety = new GenericComponentData();
1036:
1037: completeSociety.setType(ComponentData.SOCIETY);
1038: completeSociety.setName(getExperimentName()); // this should be experiment: trial FIXME
1039: completeSociety.setClassName("java.lang.Object"); // Must not be null
1040: completeSociety.setOwner(this ); // the experiment
1041: completeSociety.setParent(null);
1042: addDefaultNodeArguments(completeSociety);
1043:
1044: // For each host, add it to the society, and recurse for each of its nodes
1045: for (Iterator iter = hosts.iterator(); iter.hasNext();) {
1046: ExperimentHost host = (ExperimentHost) iter.next();
1047: ComponentData hc = new GenericComponentData();
1048: if (log.isDebugEnabled()) {
1049: log.debug("Processing Host: " + host.getShortName());
1050: }
1051: hc.setType(ComponentData.HOST);
1052: hc.setName(host.getShortName());
1053: hc.setClassName("");
1054: hc.setOwner(this );
1055: hc.setParent(completeSociety);
1056: addPropertiesAsParameters(hc, host);
1057: completeSociety.addChild(hc);
1058: NodeComponent[] nodes = host.getNodes();
1059: for (int j = 0; j < nodes.length; j++) {
1060: savedAgents.addAll(generateNodeComponent(nodes[j], hc));
1061: savedNodes.add(nodes[j]);
1062: }
1063: }
1064:
1065: // if (log.isDebugEnabled())
1066: // log.debug("genHNA: After adding assigned nodes, # saved Agents: " + savedAgents.size());
1067:
1068: // For each un-assigned Node, add it, and recurse for the Agents
1069: for (int i = 0; i < nodesToWrite.length; i++) {
1070: if (savedNodes.contains(nodesToWrite[i]))
1071: continue;
1072: savedAgents.addAll(generateNodeComponent(nodesToWrite[i],
1073: completeSociety));
1074: savedNodes.add(nodesToWrite[i]);
1075: }
1076:
1077: // if (log.isDebugEnabled())
1078: // log.debug("genHNA: After adding UN-assigned nodes, # saved Agents: " + savedAgents.size() + ", agentsToWrite is now: " + agentsToWrite.length);
1079:
1080: // For each unassigned Agent, add it
1081: for (int i = 0; i < agentsToWrite.length; i++) {
1082: if (savedAgents.contains(agentsToWrite[i])) {
1083: if (log.isDebugEnabled()) {
1084: log.debug("genHNA Already wrote Agent: "
1085: + agentsToWrite[i].getShortName());
1086: }
1087: continue;
1088: } else {
1089:
1090: // print out the FullName().toString() of all the savedAgents.
1091:
1092: if (log.isDebugEnabled()) {
1093: // log.debug("genHNA: Apparently haven't yet saved " + agentsToWrite[i]);
1094: // int j = 0;
1095: // for (Iterator ags = savedAgents.iterator(); ags.hasNext(); j++) {
1096: // AgentComponent ag = (AgentComponent)ags.next();
1097: // log.debug("savedAgent[" + j + "]: " + ag.getFullName().toString());
1098: // }
1099:
1100: log
1101: .debug("genHNA Writing Agent["
1102: + i
1103: + "]: "
1104: + agentsToWrite[i].getFullName()
1105: .toString());
1106: }
1107: generateAgentComponent(agentsToWrite[i],
1108: completeSociety, this );
1109: savedAgents.add(agentsToWrite[i]);
1110: }
1111: } // end of loop over AgentsToWrite, to catch unassigned Agents
1112:
1113: // Uncomment for very verbose output setting up HNA mapping
1114: // if (log.isDebugEnabled())
1115: // checkHNA(completeSociety, getAgents());
1116: }
1117:
1118: private void checkHNA(ComponentData data, AgentComponent[] agents) {
1119: // Look for each of the Agents in the Experiment && make
1120: // sure I can find them, and print out their parent.
1121: if (data == null) {
1122: log.debug("checkHNA got null root");
1123: return;
1124: }
1125: ComponentData[] kids = data.getChildren();
1126: for (int i = 0; i < kids.length; i++) {
1127: if (kids[i].getType().equals(ComponentData.AGENT)) {
1128: boolean foundkid = false;
1129: log.debug("checkHNA found Agent child " + kids[i]
1130: + " with parent " + data.getName());
1131: for (int j = 0; j < agents.length; j++) {
1132: if (agents[j] == null) {
1133: log
1134: .debug("checkHNA: someone already matched the "
1135: + j + " agent");
1136: continue;
1137: }
1138: log
1139: .debug("checkHNA looking to see if we found agent "
1140: + agents[j].getShortName());
1141: if (agents[j].getShortName().equals(
1142: kids[i].getName())) {
1143: log
1144: .debug("checkHNA!!! found a match for AgentComp "
1145: + agents[j].getShortName()
1146: + " with full name "
1147: + agents[j].getFullName());
1148: agents[j] = null;
1149: foundkid = true;
1150: break;
1151: }
1152: } // loop over agents
1153:
1154: // Make sure I found a real Agent for this ComponentData
1155: if (!foundkid) {
1156: log
1157: .debug("checkHNA!!!! didnt find a real AgentComp to match AgentData "
1158: + kids[i]
1159: + " in parent "
1160: + data.getName());
1161: }
1162: } else
1163: checkHNA(kids[i], agents);
1164: }
1165:
1166: // See if I found all of the Agents in the Experiment
1167: if (data == completeSociety)
1168: for (int i = 0; i < agents.length; i++) {
1169: if (agents[i] != null) {
1170: log
1171: .debug("checkHNA!!!! Never found componentData for Agent: "
1172: + agents[i].getShortName()
1173: + " with full name "
1174: + agents[i].getFullName());
1175: }
1176: }
1177: }
1178:
1179: // Use the previously inited host-node-agent ComponentData tree
1180: // in the variable 'completeSociety'
1181: // And loop through all components in the Experiment,
1182: // asking them to add their ComponentData
1183: // return the or'ed value of componentWasRemoved()
1184: final boolean askComponentsToAddCDATA() {
1185: // Now ask each component in turn to add its stuff
1186: boolean componentWasRemoved = false;
1187:
1188: BaseComponent theSoc = getSocietyComponent();
1189: if (log.isDebugEnabled()) {
1190: log.debug(theSoc.getFullName().toString()
1191: + ".addComponentData");
1192: }
1193: theSoc.addComponentData(completeSociety);
1194: componentWasRemoved |= theSoc.componentWasRemoved();
1195:
1196: for (int i = 0, n = recipes.size(); i < n; i++) {
1197: BaseComponent soc = (BaseComponent) recipes.get(i);
1198:
1199: if (log.isDebugEnabled()) {
1200: log.debug(soc.getFullName().toString()
1201: + ".addComponentData");
1202: }
1203: // Warning: This is a no-op in general
1204: // for recipes that use RecipeBase. AgentInsertion and ABCImpact
1205: // use it though. Basically, you can only use
1206: // it if you don't need a DB query to know what to do.
1207: soc.addComponentData(completeSociety);
1208:
1209: // if (log.isDebugEnabled())
1210: // log.debug("askToAdd: now complete is: " + completeSociety);
1211:
1212: // Components can notice here if they had to remove
1213: // a component (or, I suppose, modify)
1214: componentWasRemoved |= soc.componentWasRemoved();
1215: // Note that no current component returns true here
1216: }
1217: return componentWasRemoved;
1218: }
1219:
1220: public final void writeContents(String filename, OutputStream out) {
1221: createConfigWriter();
1222: try {
1223: configWriter.writeFile(filename, out);
1224: } catch (Exception e) {
1225: if (log.isErrorEnabled()) {
1226: log.error("Exception: ", e);
1227: }
1228: }
1229: }
1230:
1231: /**
1232: * An Experiment now has a configuration writer that
1233: * lets all the components write themselves out
1234: */
1235: final void createConfigWriter() {
1236: if (configWriter == null) {
1237: configWriter = new LeafOnlyConfigWriter(
1238: getSocietyComponentData());
1239: }
1240: }
1241:
1242: /**
1243: * If the experiment has at least one host with at least one node
1244: * with at least one agent, that is a configuration.
1245: *
1246: * @return a <code>boolean</code> true if it has a configured agent
1247: */
1248: public final boolean hasConfiguration() {
1249: if (hosts.isEmpty() || nodes.isEmpty() || getAgents() == null
1250: || getAgents().length == 0) {
1251: return false;
1252: }
1253: HostComponent[] hosts = getHostComponents();
1254: for (int i = 0; i < hosts.length; i++) {
1255: if (hosts[i] == null)
1256: continue;
1257: NodeComponent[] nodes = hosts[i].getNodes();
1258: for (int j = 0; j < nodes.length; j++) {
1259: if (nodes[j] == null)
1260: continue;
1261: AgentComponent[] agents = nodes[j].getAgents();
1262: if (agents.length > 0)
1263: return true;
1264: } // loop over nodes in host
1265: } // loop over hosts in experiment
1266: return false;
1267: }
1268:
1269: /**
1270: * Blindly assume the experiment has no hosts or nodes yet.
1271: * Create a host for the local host, a Node named Node0, and put
1272: * all the agents on that node on that host.
1273: */
1274: public final void createDefaultConfiguration() {
1275: // Check if it already has a node?
1276: // create one Node
1277: NodeComponent node = null;
1278:
1279: // BIG HACK IN HERE!!!!!!
1280: node = addNode("Node0");
1281: // Put all the agents in this Node
1282: // Skip agents already assigned to Nodes?
1283: AgentComponent[] agents = getAgents();
1284: for (int i = 0; i < agents.length; i++) {
1285: node.addAgent(agents[i]);
1286: }
1287:
1288: // Create one host
1289: // get this machine's name and use it
1290: String localhost = "localhost";
1291: try {
1292: localhost = java.net.InetAddress.getLocalHost()
1293: .getHostName();
1294: } catch (java.net.UnknownHostException e) {
1295: }
1296: HostComponent host = addHost(localhost);
1297:
1298: // put the one node on that host
1299: host.addNode(node);
1300: fireModification();
1301: }
1302:
1303: /**
1304: * Returns whether or not this experiment has been modified
1305: * since it was saved to the database.
1306: * @return true if experiment has been modified
1307: */
1308: public final boolean isModified() {
1309: return modified;
1310: }
1311:
1312: /**
1313: * Indicate that the experiment is up-to-date with respect to the database.
1314: * Use with caution! The only reason to reset this flag
1315: * is that when an experiment is created from the database, its components
1316: * are built-up from the database information, and thus the experiment
1317: * appears to be modified.
1318: */
1319: public final void resetModified() {
1320: modified = false;
1321: // tell listeners experiment is now saved
1322: fireModification(new ModificationEvent(this ,
1323: ExperimentBase.EXPERIMENT_SAVED));
1324: }
1325:
1326: /**
1327: * Sets the current Trial ID.
1328: *
1329: * @param trialID - New Trial ID
1330: */
1331: final void setTrialID(String trialID) {
1332: if (this .trialID == trialID)
1333: return;
1334: this .trialID = trialID;
1335: defaultNodeArguments
1336: .setReadOnlyProperty(EXPERIMENT_ID, trialID);
1337: fireModification();
1338: }
1339:
1340: public final String getTrialID() {
1341: if (DBUtils.dbMode) {
1342: return trialID;
1343: } else {
1344: return null;
1345: }
1346: }
1347:
1348: /**
1349: * Sets the Experiment ID for this Experiment.
1350: *
1351: * @param expID
1352: */
1353: public final void setExperimentID(String expID) {
1354: if (this .expID == expID)
1355: return;
1356: this .expID = expID;
1357: fireModification();
1358: }
1359:
1360: public final String getExperimentID() {
1361: if (DBUtils.dbMode) {
1362: return expID;
1363: } else {
1364: return null;
1365: }
1366: }
1367:
1368: /**
1369: * get the local variable idea of the community assembly for this
1370: * experiment, possibly null
1371: */
1372: public final String getCommAsbID() {
1373: return commAsb;
1374: }
1375:
1376: /**
1377: * (Re) set the local variables idea of the community assembly for
1378: * this experiment, possibly to null
1379: */
1380: public final void setCommAsbID(String id) {
1381: this .commAsb = id;
1382: }
1383:
1384: /**
1385: * Imports a HNA XML file. The file is imported into
1386: * a <code>ComponentData</code> structure which is then
1387: * traversed and applied to the current experiment.
1388: *
1389: * @param parent - Parent GUI Component
1390: */
1391: public final void importHNA(Component parent) {
1392: File resultDir = getResultDirectory();
1393: String path = ".";
1394: if (resultDir != null)
1395: path = resultDir.getAbsolutePath();
1396: JFileChooser chooser = new JFileChooser(path);
1397: chooser.setDialogTitle("Select HNA Export file to apply");
1398: chooser
1399: .setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
1400: chooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
1401: public boolean accept(final File f) {
1402: return (f.isDirectory() || (f.isFile())
1403: && f.canRead()
1404: && (f.getName().endsWith("xml") || f.getName()
1405: .endsWith("XML")));
1406: }
1407:
1408: public String getDescription() {
1409: return "HNA XML Files";
1410: }
1411: });
1412: File file = null;
1413: while (file == null) {
1414: int result = chooser.showDialog(parent, "OK");
1415: if (result != JFileChooser.APPROVE_OPTION)
1416: return;
1417: file = chooser.getSelectedFile();
1418: if (file != null && (!file.canRead() || file.isDirectory()))
1419: file = null;
1420: }
1421:
1422: if (log.isInfoEnabled()) {
1423: log.info("importing HNA file " + file.getAbsolutePath());
1424: }
1425:
1426: // FIXME: Put up a dialog indicating the file being imported?
1427: // Bug 1765
1428:
1429: ComponentData mapping = null;
1430: ExperimentXML parser = new ExperimentXML();
1431: mapping = parser.parseExperimentFile(file);
1432: if (mapping == null) {
1433: if (log.isErrorEnabled()) {
1434: log.error("Error parsing file: " + file.getName());
1435: }
1436: // Display an error dialog here!
1437: return;
1438: }
1439:
1440: if (mapping.getType().equals(ComponentData.SOCIETY)) {
1441: addChildren(mapping.getChildren());
1442: } else {
1443: if (log.isErrorEnabled()) {
1444: log.error("Didn't start with a society!");
1445: }
1446: }
1447: }
1448:
1449: /**
1450: * Adds new children to the experiment components
1451: * based on the NHA mappings loaded in from a file.
1452: *
1453: * @param children - Child Component to re-map.
1454: */
1455: private void addChildren(final ComponentData[] children) {
1456: if (children == null)
1457: return;
1458: for (int i = 0; i < children.length; i++) {
1459: final ComponentData child = children[i];
1460: if (child == null)
1461: continue;
1462: if (child.getType().equals(ComponentData.HOST)) {
1463: // Add host.
1464: HostComponent host = null;
1465: try {
1466: host = addHost(child.getName());
1467: } catch (IllegalArgumentException e) {
1468: // Host already exists.
1469: final HostComponent[] allHosts = getHostComponents();
1470: if (allHosts == null)
1471: continue;
1472: for (int x = 0; x < allHosts.length; x++) {
1473: if (allHosts[x].getShortName().equals(
1474: child.getName())) {
1475: host = allHosts[x];
1476: break;
1477: }
1478: }
1479: if (log.isDebugEnabled()) {
1480: log.debug("Host already exists: "
1481: + child.getName());
1482: }
1483: }
1484: if (host != null)
1485: addHostChildren(child.getChildren(), host);
1486: } else if (child.getType().equals(ComponentData.NODE)) {
1487: // Add node.
1488: NodeComponent node = null;
1489: try {
1490: node = addNode(child.getName());
1491: } catch (IllegalArgumentException e) {
1492: // Node already exists.
1493: final NodeComponent[] allNodes = getNodeComponents();
1494: if (allNodes == null)
1495: continue;
1496: for (int x = 0; x < allNodes.length; x++) {
1497: if (allNodes[x].getShortName().equals(
1498: child.getName())) {
1499: node = allNodes[x];
1500: break;
1501: }
1502: }
1503: if (log.isDebugEnabled()) {
1504: log.debug("Node already exists: "
1505: + child.getName());
1506: }
1507: }
1508: if (node != null)
1509: addNodeChildren(child.getChildren(), node);
1510: } else if (child.getType().equals(ComponentData.AGENT)) {
1511: // Ignore.
1512: } else {
1513: if (log.isWarnEnabled()) {
1514: log.warn("Unknown Type: " + child.getType());
1515: }
1516: }
1517: }
1518: }
1519:
1520: /**
1521: * Adds all new children to the HostComponent
1522: *
1523: * @param children All children of the new HostComponent.
1524: * @param host - HostComponent to add children to.
1525: */
1526: private void addHostChildren(ComponentData[] children,
1527: HostComponent host) {
1528: if (children == null)
1529: return;
1530: if (host == null)
1531: return;
1532: for (int i = 0; i < children.length; i++) {
1533: boolean foundInHost = false;
1534: boolean foundInSociety = false;
1535: ComponentData child = children[i];
1536: if (child == null)
1537: return;
1538: NodeComponent expNode = null;
1539: NodeComponent[] allNodes = getNodeComponents();
1540: if (child.getType().equals(ComponentData.NODE)) {
1541: if (allNodes != null) {
1542: for (int k = 0; k < allNodes.length; k++) {
1543: if (allNodes[k] == null)
1544: continue;
1545: if (child.getName().equals(
1546: allNodes[k].getShortName())) {
1547: foundInSociety = true;
1548: expNode = allNodes[k];
1549: break;
1550: }
1551: }
1552: }
1553: NodeComponent[] crntNodes = host.getNodes();
1554: if (crntNodes != null) {
1555: for (int j = 0; j < crntNodes.length; j++) {
1556: if (crntNodes[j] == null)
1557: continue;
1558: if (child.getName().equals(
1559: crntNodes[j].getShortName())) {
1560: foundInHost = true;
1561: break;
1562: }
1563: }
1564: }
1565: if (!foundInHost) {
1566: // See if in Exp.
1567: if (foundInSociety) {
1568: expNode = host.addNode(expNode);
1569: } else {
1570: expNode = host
1571: .addNode(addNode(child.getName()));
1572: }
1573: }
1574: if (expNode != null)
1575: addNodeChildren(child.getChildren(), expNode);
1576: } else {
1577: if (log.isWarnEnabled()) {
1578: log.warn("Unknown child of host: "
1579: + child.getName());
1580: }
1581: }
1582: }
1583: }
1584:
1585: /**
1586: * Adds all children to the Node.
1587: *
1588: * @param children All new children for the node.
1589: * @param node Node to add children to.
1590: */
1591: private void addNodeChildren(ComponentData[] children,
1592: NodeComponent node) {
1593: if (node == null)
1594: return;
1595: if (children == null)
1596: return;
1597:
1598: for (int i = 0; i < children.length; i++) {
1599: boolean foundInSociety = false;
1600: boolean foundInNode = false;
1601: ComponentData child = children[i];
1602: if (child == null)
1603: continue;
1604: AgentComponent[] allAgents = getAgents();
1605: AgentComponent addAgent = null;
1606: if (child.getType().equals(ComponentData.AGENT)) {
1607: if (allAgents != null) {
1608: for (int k = 0; k < allAgents.length; k++) {
1609: if (allAgents[k] == null)
1610: continue;
1611: if (child.getName().equals(
1612: allAgents[k].getShortName())) {
1613: foundInSociety = true;
1614: addAgent = allAgents[k];
1615: break;
1616: }
1617: }
1618: }
1619:
1620: if (foundInSociety) {
1621: AgentComponent[] crntAgents = node.getAgents();
1622: if (crntAgents != null) {
1623: for (int j = 0; j < crntAgents.length; j++) {
1624: if (crntAgents[j] == null)
1625: continue;
1626: if (child.getName().equals(
1627: crntAgents[j].getShortName())) {
1628: foundInNode = true;
1629: break;
1630: }
1631: }
1632: }
1633: if (!foundInNode) {
1634: if (addAgent == null) {
1635: // this shouldnt happen
1636: } else {
1637: // FIXME: This test not quite adequate - must
1638: // check that agent name not same as any
1639: // other Node or Agent name
1640: if (node.getShortName().equalsIgnoreCase(
1641: addAgent.getShortName())) {
1642: if (log.isWarnEnabled()) {
1643: log
1644: .warn("Agent name same as node, cannot perform addition");
1645: }
1646: JOptionPane
1647: .showMessageDialog(
1648: null,
1649: "Cannot Map Agent to Node of Same name, ignoring agent: "
1650: + addAgent
1651: .getShortName());
1652: } else {
1653: node.addAgent(addAgent);
1654: }
1655: }
1656: }
1657: } else {
1658: JOptionPane.showMessageDialog(null,
1659: "Cannot Map Unknown Agent: "
1660: + child.getName());
1661: if (log.isWarnEnabled()) {
1662: log.warn("Agent: " + child.getName()
1663: + " not known. Add aborted");
1664: }
1665: }
1666: } else {
1667: if (log.isWarnEnabled()) {
1668: log.warn("Unknown child of node: "
1669: + child.getName());
1670: }
1671: }
1672: }
1673: }
1674:
1675: public abstract void save(DBConflictHandler ch);
1676:
1677: protected abstract void setDefaultNodeArguments();
1678:
1679: final class MyModificationListener implements ModificationListener,
1680: ConfigurableComponentListener {
1681: // tell listeners on experiment that experiment was modified
1682: public void modified(ModificationEvent e) {
1683: notifyExperimentListeners(e);
1684: }
1685: }
1686: }
|