001: /*
002: * <copyright>
003: *
004: * Copyright 1997-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: /**
028: * Add[/Remove] Assets GUI Plugin.
029: * <p>
030: * Parameters:<br>
031: * <ul>
032: * <li>"*.xml": name of XML file containing prototype names.</li>
033: * <li>"true": set allowRemoveAssets to true</li>
034: * <li>"false": set allowRemoveAssets to false</li>
035: * </ul>
036: * <p>
037: * If boolean "allowRemoveAssets" is false, then the random remove
038: * assets feature is turned off. Randomly removing assets is
039: * likely only useful for testing!
040: * <p>
041: * The initial prototype ID list is read from an XML file, either
042: * the DEFAULT_XML_FILE_STRING or the plugin parameter. The XML
043: * input expected DTD is:<br>
044: * <pre>
045: * <!ELEMENT prototypes (name)*>
046: * <!ELEMENT name (#PCDATA)>
047: * </pre>
048: * and, as an example:<br>
049: * <pre>
050: * <?xml version="1.0" encoding="US-ASCII"?>
051: * <!DOCTYPE prototypes SYSTEM "AddPrototypes.dtd" []>
052: * <prototypes>
053: * <name>NSN/2350010871095</name>
054: * <name>mos-88m</name>
055: * </prototypes>
056: * </pre>
057: */package org.cougaar.mlm.plugin.sample;
058:
059: /*
060: * Imports
061: */
062: import java.awt.BorderLayout;
063: import java.awt.Color;
064: import java.awt.FlowLayout;
065: import java.awt.GridBagConstraints;
066: import java.awt.GridBagLayout;
067: import java.awt.GridLayout;
068: import java.awt.Insets;
069: import java.awt.event.ActionEvent;
070: import java.awt.event.ActionListener;
071: import java.awt.event.ItemEvent;
072: import java.awt.event.ItemListener;
073: import java.io.FileInputStream;
074: import java.util.Date;
075: import java.util.Enumeration;
076: import java.util.Vector;
077:
078: import javax.swing.JButton;
079: import javax.swing.JCheckBox;
080: import javax.swing.JComboBox;
081: import javax.swing.JFrame;
082: import javax.swing.JLabel;
083: import javax.swing.JPanel;
084: import javax.swing.JTextField;
085:
086: import org.apache.xerces.parsers.DOMParser;
087: import org.cougaar.core.blackboard.IncrementalSubscription;
088: import org.cougaar.planning.ldm.PlanningFactory;
089: import org.cougaar.planning.ldm.asset.AggregateAsset;
090: import org.cougaar.planning.ldm.asset.Asset;
091: import org.cougaar.planning.ldm.asset.TypeIdentificationPG;
092: import org.cougaar.planning.ldm.plan.RoleScheduleImpl;
093: import org.cougaar.planning.ldm.plan.Schedule;
094: import org.cougaar.planning.plugin.legacy.SimplePlugin;
095: import org.cougaar.util.ShortDateFormat;
096: import org.cougaar.util.UnaryPredicate;
097: import org.w3c.dom.Document;
098: import org.w3c.dom.Element;
099: import org.w3c.dom.Node;
100: import org.w3c.dom.NodeList;
101: import org.xml.sax.InputSource;
102:
103: public final class AddAssetsGUIPlugin extends SimplePlugin {
104:
105: /** CONFIGURATION **/
106: private static final boolean DEFAULT_ALLOW_REMOVE_ASSETS = false;
107: private static final String DEFAULT_XML_FILE_STRING = "AddPrototypes.xml";
108: private static final int DEFAULT_END_DATE_MONTH_DELTA = 3;
109:
110: /** Allow asset removal **/
111: private boolean allowRemoveAssets;
112:
113: /** Create Aggregates on request **/
114: private boolean createAggregates = false;
115:
116: /** GUI Components **/
117: private JComboBox prototypeNameCombo;
118: private JButton addButton;
119: private JTextField addQuantityText;
120: private JTextField addBeginText;
121: private JTextField addEndText;
122: private JCheckBox aggregateCheckBox;
123: private JButton removeButton;
124: private JLabel statusLabel;
125:
126: /** Vector of known prototype names **/
127: private Vector prototypeNames;
128:
129: private ShortDateFormat dateFormatter;
130:
131: private PlanningFactory ldmf_ = null;
132:
133: private IncrementalSubscription removableAssetsSub;
134:
135: /**
136: * The public constructor with no args to set the default values.
137: **/
138: public AddAssetsGUIPlugin() {
139: }
140:
141: protected void execute() {
142: }
143:
144: /**
145: * Load the data from the file synchronously.
146: * We'll not actually do anything later on.
147: **/
148: protected void setupSubscriptions() {
149: // default configuration;
150: String XMLFileString = DEFAULT_XML_FILE_STRING;
151: allowRemoveAssets = DEFAULT_ALLOW_REMOVE_ASSETS;
152:
153: // read parameters:
154: // XMLFileString: name of file containing prototype names
155: // allowRemoveAssets: allow remove assets
156: Enumeration eParams = getParameters().elements();
157: while (eParams.hasMoreElements()) {
158: String sParam = (String) eParams.nextElement();
159: if (sParam.endsWith(".xml")) {
160: XMLFileString = sParam;
161: } else if (sParam.equals("true")) {
162: allowRemoveAssets = true;
163: } else if (sParam.equals("false")) {
164: allowRemoveAssets = false;
165: }
166: }
167:
168: createGUI(XMLFileString);
169: ldmf_ = getFactory();
170:
171: if (allowRemoveAssets) {
172: removableAssetsSub = (IncrementalSubscription) subscribe(newRemovableAssetsPred());
173: }
174: }
175:
176: protected void setStatus(String s) {
177: setStatus(false, s);
178: }
179:
180: protected void setStatus(boolean success, String s) {
181: statusLabel
182: .setForeground((success ? Color.darkGray : Color.red));
183: statusLabel.setText(s);
184: }
185:
186: protected void watchAddButton() {
187: String prototypeName = (String) prototypeNameCombo
188: .getSelectedItem();
189: if (prototypeName == null) {
190: setStatus("No asset type selected");
191: return;
192: }
193: prototypeName = prototypeName.trim();
194: if (prototypeName.length() < 1) {
195: setStatus("No asset type selected");
196: return;
197: }
198:
199: int quantity;
200: Date beginDate;
201: Date endDate;
202:
203: try {
204: quantity = Integer.parseInt(addQuantityText.getText()
205: .trim());
206: } catch (Exception quantE) {
207: quantity = -1;
208: }
209: if (quantity < 0) {
210: setStatus("Invalid quantity");
211: } else if (quantity == 0) {
212: setStatus(true, "Added Nothing");
213: } else if ((beginDate = dateFormatter.toDate(addBeginText
214: .getText().trim())) == null) {
215: setStatus("Invalid begin date");
216: } else if ((endDate = dateFormatter.toDate(addEndText.getText()
217: .trim())) == null) {
218: setStatus("Invalid end date");
219: } else {
220: openTransaction();
221: try {
222: addAsset(prototypeName, quantity, beginDate, endDate);
223: setStatus(true, "Added "
224: + ((quantity > 1) ? (quantity + " Assets")
225: : "One Asset"));
226: if (!prototypeNames.contains(prototypeName)) {
227: prototypeNames.add(prototypeName);
228: prototypeNameCombo.addItem(prototypeName);
229: }
230: } catch (Exception exc) {
231: if (prototypeNames.contains(prototypeName)) {
232: prototypeNames.remove(prototypeName);
233: prototypeNameCombo.removeItem(prototypeName);
234: }
235: System.err.println("Could not add asset: " + exc);
236: setStatus("Unable to add Asset Type");
237: }
238: closeTransactionDontReset();
239: }
240: }
241:
242: protected void watchRemoveButton() {
243: if (!allowRemoveAssets) {
244: return;
245: }
246: String prototypeName = (String) prototypeNameCombo
247: .getSelectedItem();
248: if (prototypeName != null) {
249: prototypeName = prototypeName.trim();
250: if ((prototypeName.length() < 1)
251: || prototypeName.equals("*"))
252: prototypeName = null;
253: }
254: openTransaction();
255: try {
256: int removeCount = removeAsset(prototypeName);
257: if (removeCount > 1)
258: setStatus(true, "Removed " + removeCount
259: + " random Assets");
260: else if (removeCount > 0)
261: setStatus(true, "Removed a random Asset");
262: else {
263: setStatus(true, "Zero \"" + prototypeName
264: + "\" assets (try typeID!)");
265: prototypeNames.remove(prototypeName);
266: prototypeNameCombo.removeItem(prototypeName);
267: }
268: if ((prototypeName != null)
269: && (!prototypeNames.contains(prototypeName))) {
270: prototypeNames.add(prototypeName);
271: prototypeNameCombo.addItem(prototypeName);
272: }
273: } catch (Exception exc) {
274: if ((prototypeName != null)
275: && prototypeNames.contains(prototypeName)) {
276: prototypeNames.remove(prototypeName);
277: prototypeNameCombo.removeItem(prototypeName);
278: }
279: System.err.println("Could not remove asset of name: "
280: + prototypeName);
281: setStatus("Unable to remove \"" + prototypeName
282: + "\n Asset");
283: }
284: closeTransactionDontReset();
285: }
286:
287: /** An ActionListener that listens to the buttons. */
288: class AddButtonListener implements ActionListener {
289: public void actionPerformed(ActionEvent e) {
290: JButton button = (JButton) e.getSource();
291: if (button == addButton)
292: watchAddButton();
293: else
294: watchRemoveButton();
295: }
296: }
297:
298: /** An ItemListener that listens to the Aggregates CheckBox */
299: class AggregateListener implements ItemListener {
300: public void itemStateChanged(ItemEvent e) {
301: createAggregates = (e.getStateChange() == ItemEvent.SELECTED);
302: }
303: }
304:
305: private String getClusterID() {
306: try {
307: return getAgentIdentifier().toString();
308: } catch (Exception e) {
309: return "<UNKNOWN>";
310: }
311: }
312:
313: private void createGUI(String XMLFileString) {
314: // read initial asset prototype names
315: if (XMLFileString != null)
316: prototypeNames = readInitialPrototypeNames(XMLFileString);
317: if (prototypeNames == null)
318: prototypeNames = new Vector();
319: if (prototypeNames.size() == 0)
320: prototypeNames.add(" ");
321:
322: // create buttons, labels, etc
323: prototypeNameCombo = new JComboBox(prototypeNames);
324: prototypeNameCombo.setEditable(true);
325: addButton = new JButton("Add Asset");
326: addButton.addActionListener(new AddButtonListener());
327: addQuantityText = new JTextField(3);
328: addBeginText = new JTextField(10);
329: addEndText = new JTextField(10);
330: aggregateCheckBox = new JCheckBox("Create AggregateAsset",
331: false);
332: aggregateCheckBox.addItemListener(new AggregateListener());
333: addQuantityText.setText("1");
334: dateFormatter = new ShortDateFormat();
335: addBeginText.setText(dateFormatter.toString(null));
336: addEndText.setText(dateFormatter.toString(dateFormatter
337: .adjustDate(null, DEFAULT_END_DATE_MONTH_DELTA, 0)));
338: if (allowRemoveAssets) {
339: removeButton = new JButton("Remove Random Asset");
340: removeButton.addActionListener(new AddButtonListener());
341: }
342: statusLabel = new JLabel("< >");
343:
344: // do layout
345: JFrame frame = new JFrame("AddAssetsGUIPlugin "
346: + getClusterID());
347: frame.setLocation(0, 0);
348: frame.getContentPane().setLayout(new FlowLayout());
349: JPanel rootPanel = new JPanel();
350: GridBagLayout gbl = new GridBagLayout();
351: GridBagConstraints gbc = new GridBagConstraints();
352: gbc.insets = new Insets(15, 15, 15, 15);
353: gbc.fill = GridBagConstraints.BOTH;
354: rootPanel.setLayout(gbl);
355:
356: JPanel protoNamePanel = new JPanel();
357: protoNamePanel.setLayout(new GridLayout(2, 1));
358: JLabel protoNameLabel = new JLabel("Prototype Name:");
359: protoNameLabel.setForeground(Color.blue);
360: protoNamePanel.add(protoNameLabel);
361: protoNamePanel.add(prototypeNameCombo);
362: gbl.setConstraints(protoNamePanel, gbc);
363: rootPanel.add(protoNamePanel);
364:
365: JPanel addPanel = new JPanel();
366: addPanel.setLayout(new BorderLayout());
367: JLabel addLabel = new JLabel("Add Assets:");
368: addLabel.setForeground(Color.blue);
369: addPanel.add(addLabel, BorderLayout.NORTH);
370: JPanel addOptsPanel = new JPanel();
371: addOptsPanel.setLayout(new BorderLayout());
372: JPanel addOptsTextPanel = new JPanel();
373: addOptsTextPanel.setLayout(new GridLayout(4, 1));
374: addOptsTextPanel.add(new JLabel("Quantity:"));
375: addOptsTextPanel.add(new JLabel("Begin Date:"));
376: addOptsTextPanel.add(new JLabel("End Date:"));
377: addOptsTextPanel.add(new JLabel(""));
378: JPanel addOptsValuePanel = new JPanel();
379: addOptsValuePanel.setLayout(new GridLayout(4, 1));
380: addOptsValuePanel.add(addQuantityText);
381: addOptsValuePanel.add(addBeginText);
382: addOptsValuePanel.add(addEndText);
383: addOptsValuePanel.add(aggregateCheckBox);
384: addOptsPanel.add(addOptsTextPanel, BorderLayout.CENTER);
385: addOptsPanel.add(addOptsValuePanel, BorderLayout.EAST);
386: addPanel.add(addOptsPanel, BorderLayout.CENTER);
387: addPanel.add(addButton, BorderLayout.SOUTH);
388: gbc.gridy = 1;
389: gbl.setConstraints(addPanel, gbc);
390: rootPanel.add(addPanel);
391:
392: if (allowRemoveAssets) {
393: JPanel removePanel = new JPanel();
394: removePanel.setLayout(new GridLayout(2, 1));
395: JLabel removeLabel = new JLabel("Remove Random Asset:");
396: removeLabel.setForeground(Color.blue);
397: removePanel.add(removeLabel);
398: removePanel.add(removeButton);
399: gbc.gridy = 2;
400: gbl.setConstraints(removePanel, gbc);
401: rootPanel.add(removePanel);
402: }
403:
404: JPanel statusPanel = new JPanel();
405: statusPanel.setLayout(new GridLayout(2, 1));
406: JLabel statusLabelLabel = new JLabel("Status:");
407: statusLabelLabel.setForeground(Color.blue);
408: statusPanel.add(statusLabelLabel);
409: statusPanel.add(statusLabel);
410: gbc.gridy = 3 + (allowRemoveAssets ? 1 : 0);
411: gbl.setConstraints(statusPanel, gbc);
412: rootPanel.add(statusPanel);
413:
414: frame.getContentPane().add(rootPanel);
415: frame.pack();
416: frame.setVisible(true);
417:
418: setStatus(true, "Ready");
419: }
420:
421: private Vector readInitialPrototypeNames(String xmlFileString) {
422: DOMParser parser = new DOMParser();
423: try {
424: parser.parse(new InputSource(new FileInputStream(
425: xmlFileString)));
426: } catch (java.io.IOException ioe) {
427: ioe.printStackTrace();
428: return null;
429: } catch (org.xml.sax.SAXException sae) {
430: sae.printStackTrace();
431: return null;
432: }
433:
434: Document document = parser.getDocument();
435: Element root = document.getDocumentElement();
436:
437: if (!"prototypes".equals(root.getNodeName())) {
438: System.err.println("Bad XML root: " + root.getNodeName()
439: + " != prototypes");
440: return null;
441: }
442:
443: Vector assetsV = new Vector();
444:
445: NodeList nlist = root.getChildNodes();
446: int nlength = nlist.getLength();
447: for (int i = 0; i < nlength; i++) {
448: Node subNode = (Node) nlist.item(i);
449: if ((subNode.getNodeType() == Node.ELEMENT_NODE)
450: && ("name".equals(subNode.getNodeName()))) {
451: String value = subNode.getFirstChild().getNodeValue()
452: .trim();
453: assetsV.add(value);
454: }
455: }
456:
457: return assetsV;
458: }
459:
460: private static int counter = 0;
461:
462: /**
463: * add one or an aggregate of the given type_id
464: * @param type_id asset prototype id name
465: * @param quantity how many to add
466: * @param beginDate schedule availability start date
467: * @param endDate schedule availability stop date
468: * @param createAggregates : Should we create aggregate asset, or individuals?
469: */
470: private void addAsset(String type_id, int quantity, Date beginDate,
471: Date endDate) {
472: //System.out.println("ADD "+type_id+
473: // " quantity: "+quantity+" begin: "+beginDate+" end: "+endDate);
474: Asset newAsset;
475:
476: for (int i = 0; i < quantity; i++) {
477:
478: if (createAggregates) {
479: AggregateAsset multiAsset = (AggregateAsset) ldmf_
480: .createAggregate(type_id, quantity);
481: newAsset = multiAsset;
482: } else {
483: Asset singleAsset = (Asset) ldmf_.createInstance(
484: type_id, ("obj-" + (++counter)));
485: newAsset = singleAsset;
486: }
487:
488: RoleScheduleImpl newRoleS = (RoleScheduleImpl) (newAsset
489: .getRoleSchedule());
490: Schedule newSched = ldmf_.newSimpleSchedule(beginDate,
491: endDate);
492: newRoleS.setAvailableSchedule(newSched);
493: publishAdd(newAsset);
494:
495: // Just create a single aggregate asset if CreateAggregates = true
496: if (createAggregates)
497: break;
498: }
499: }
500:
501: /**
502: * Remove some random asset of the given type.
503: *
504: * Note: This doesn't seem to do the right thing when the
505: * asset is in an Aggregate. Do we want to remove the entire
506: * aggregate or modify it's number of elements?
507: *
508: * @param type_id asset prototype id name
509: * @return number of assets removed
510: */
511: private int removeAsset(String type_id) {
512: // count assets of given type_id
513: int nAssets;
514: Enumeration eAssets;
515: if (type_id == null) {
516: nAssets = removableAssetsSub.size();
517: eAssets = removableAssetsSub.elements();
518: } else {
519: Vector v = new Vector();
520: Enumeration e = removableAssetsSub.elements();
521: while (e.hasMoreElements()) {
522: Asset a = (Asset) e.nextElement();
523: while (a instanceof AggregateAsset)
524: a = ((AggregateAsset) a).getAsset();
525: Asset pt = a.getPrototype();
526: if (pt != null) {
527: TypeIdentificationPG tpg = pt
528: .getTypeIdentificationPG();
529: if (tpg != null) {
530: if (type_id.equals(tpg.getTypeIdentification())) {
531: v.addElement(a);
532: }
533: }
534: }
535: }
536: nAssets = v.size();
537: eAssets = v.elements();
538: }
539: if (nAssets > 0) {
540: // pick one to remove
541: int j = (int) (nAssets * Math.random());
542: if (j >= nAssets)
543: j = nAssets - 1;
544: try {
545: // skip to it
546: for (int k = j; k > 0; k--)
547: eAssets.nextElement();
548: // remove it
549: Asset removeA = (Asset) eAssets.nextElement();
550: System.out.println("Remove asset #" + j + " "
551: + removeA);
552: publishRemove(removeA);
553: } catch (Exception ex) {
554: System.out.println("Failed to remove asset #" + j);
555: }
556: // if it's an aggregate, should we return it's quantity?
557: return 1;
558: } else {
559: System.out.println("No assets of type: " + type_id);
560: return 0;
561: }
562: }
563:
564: private static UnaryPredicate newRemovableAssetsPred() {
565: return new UnaryPredicate() {
566: public boolean execute(Object o) {
567: while (o instanceof AggregateAsset)
568: o = ((AggregateAsset) o).getAsset();
569: return (o instanceof Asset);
570: }
571: };
572: }
573: }
|