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: package org.cougaar.glm.execution.eg;
027:
028: import javax.swing.table.AbstractTableModel;
029: import javax.swing.Action;
030: import javax.swing.AbstractAction;
031: import javax.swing.JCheckBox;
032: import javax.swing.JButton;
033: import javax.swing.JPanel;
034: import java.awt.event.ActionEvent;
035: import java.awt.GridBagLayout;
036: import java.awt.GridBagConstraints;
037: import java.awt.event.ActionListener;
038: import java.awt.Component;
039: import java.io.IOException;
040: import java.io.FileNotFoundException;
041: import java.io.FileWriter;
042: import java.io.PrintWriter;
043: import java.util.ArrayList;
044: import java.util.List;
045: import java.util.Arrays;
046: import java.util.Calendar;
047: import java.util.Collection;
048: import java.util.Date;
049: import java.util.GregorianCalendar;
050: import java.util.Iterator;
051: import java.util.SortedSet;
052: import java.util.TreeSet;
053: import java.util.HashMap;
054: import java.util.Properties;
055: import java.util.Enumeration;
056: import javax.swing.JComponent;
057: import org.cougaar.util.OptionPane;
058: import org.cougaar.glm.execution.common.*;
059:
060: /**
061: * Keeps track of the inventory report schedules and decide if/when to
062: * generate a report.
063: **/
064: public abstract class ManagerBase {
065: protected EventGenerator theEventGenerator;
066: private TreeSet rawSchedule = new TreeSet();
067: protected FilteredSet schedule = new FilteredSet(rawSchedule);
068: private boolean scheduleChanged = false;
069: protected ManagerTableModel tableModel = null;
070: protected HashMap map = new HashMap();
071: private FilterGUI theFilterGUI = null;
072: private ReportManagerGUI theReportManagerGUI;
073: private List plugins = new ArrayList();
074: private PrintWriter logWriter = null;
075: protected static final String LOGFILE_SUFFIX = ".tsv";
076:
077: public ManagerBase(EventGenerator anEventGenerator) {
078: theEventGenerator = anEventGenerator;
079: installPlugins();
080: }
081:
082: public void enableLog(String prefix) throws IOException {
083: logWriter = new PrintWriter(new FileWriter(
084: getLogFileName(prefix)), true);
085: writeLogHeader();
086: }
087:
088: protected abstract String getLogFileName(String prefix);
089:
090: /**
091: * Get the class of the default plugin. Override this if this
092: * manager has a default plugin.
093: * @return null if there is no default else the class of the default
094: * plugin.
095: **/
096: protected Class getDefaultPluginClass() {
097: return null;
098: }
099:
100: /**
101: * Get the interface of the plugins for this manager. Override this
102: * if this manager has plugins.
103: * @return null if there are no plugins else the class of the plugin interface
104: **/
105: protected Class getPluginInterface() {
106: return null;
107: }
108:
109: /**
110: * Install plugins
111: **/
112: private void installPlugins() {
113: Class pluginInterface = getPluginInterface();
114: if (pluginInterface == null)
115: return; // This manager has no plugins
116: Class defaultPluginClass = getDefaultPluginClass();
117: for (Iterator i = theEventGenerator
118: .getPluginSpecifications(pluginInterface); i.hasNext();) {
119: PluginSpecification plugInSpecification = (PluginSpecification) i
120: .next();
121: try {
122: Class plugInClass = plugInSpecification
123: .getPluginClass();
124: if (plugInClass == defaultPluginClass)
125: continue; // Do later
126: Plugin plugin = (Plugin) plugInClass.newInstance();
127: boolean disabled = true; // All plugins disabled by default
128: String parameter = plugInSpecification.getParameter();
129: if (parameter != null)
130: plugin.setParameter(parameter);
131: if (theEventGenerator != null)
132: plugin.setEventGenerator(theEventGenerator);
133: addPlugin(plugin, disabled);
134: } catch (Exception e) {
135: System.err.println("Exception creating "
136: + pluginInterface.getName() + ": " + e);
137: e.printStackTrace();
138: }
139: }
140: try {
141: addPlugin((Plugin) defaultPluginClass.newInstance(), false);
142: } catch (Exception e) {
143: System.err.println("Exception creating "
144: + defaultPluginClass + ": " + e);
145: e.printStackTrace();
146: }
147: }
148:
149: public final ReportManagerGUI getGUI() {
150: if (theReportManagerGUI == null) {
151: theReportManagerGUI = new ReportManagerGUI(getTableModel(),
152: this );
153: Action filterAction = new AbstractAction("Filter...") {
154: public void actionPerformed(ActionEvent e) {
155: FilterGUI filterGUI = getFilterGUI();
156: int ok = OptionPane.showOptionDialog(
157: theReportManagerGUI, filterGUI,
158: "Filter Properties",
159: OptionPane.OK_CANCEL_OPTION,
160: OptionPane.QUESTION_MESSAGE, null, null,
161: null);
162: if (ok == OptionPane.OK_OPTION) {
163: schedule.clearFilters();
164: filterGUI.addFilters(schedule);
165: tableModel.fireTableDataChanged();
166: }
167: }
168: };
169: theReportManagerGUI.addToToolBar(filterAction)
170: .setToolTipText("Edit report filter");
171: if (plugins.size() > 0) {
172: theReportManagerGUI.addToToolBar(getPluginButton());
173: }
174: List toolBarItems = getToolBarItems();
175: for (Iterator i = toolBarItems.iterator(); i.hasNext();) {
176: Object item = i.next();
177: if (item instanceof Action) {
178: theReportManagerGUI.addToToolBar((Action) item);
179: } else if (item instanceof Component) {
180: theReportManagerGUI.addToToolBar((Component) item);
181: }
182: }
183: }
184: return theReportManagerGUI;
185: }
186:
187: public abstract String getGUITitle();
188:
189: public void save(Properties props, String prefix) {
190: prefix += getGUITitle() + ".";
191: props.setProperty(prefix + "autosend", isAutoSend() ? "true"
192: : "false");
193: props.setProperty(prefix + "autosendInvisible",
194: isAutoSendInvisible() ? "true" : "false");
195: getFilterGUI().save(props, prefix + "filter.");
196: for (Iterator i = plugins.iterator(); i.hasNext();) {
197: PluginItem plugInItem = (PluginItem) i.next();
198: String piPrefix = prefix + "plugin."
199: + plugInItem.thePlugin.getPluginName() + ".";
200: props.setProperty(piPrefix + "selected", plugInItem
201: .isSelected() ? "true" : "false");
202: plugInItem.thePlugin.save(props, piPrefix);
203: }
204: }
205:
206: public static boolean getBooleanProperty(Properties props,
207: String name) {
208: return getBooleanProperty(props, name, false);
209: }
210:
211: public static boolean getBooleanProperty(Properties props,
212: String name, boolean dflt) {
213: String value = props.getProperty(name);
214: if (value == null)
215: return dflt;
216: return new Boolean(value).booleanValue();
217: }
218:
219: public void restore(Properties props, String prefix) {
220: prefix += getGUITitle() + ".";
221: setAutoSend(getBooleanProperty(props, prefix + "autosend"));
222: setAutoSendInvisible(getBooleanProperty(props, prefix
223: + "autosendInvisible"));
224: getFilterGUI().restore(props, prefix + "filter.");
225: schedule.clearFilters();
226: getFilterGUI().addFilters(schedule);
227: for (Iterator i = plugins.iterator(); i.hasNext();) {
228: PluginItem plugInItem = (PluginItem) i.next();
229: String piPrefix = prefix + "plugin."
230: + plugInItem.thePlugin.getPluginName() + ".";
231: plugInItem.setSelected(getBooleanProperty(props, piPrefix
232: + "selected"));
233: plugInItem.thePlugin.restore(props, piPrefix);
234: }
235: }
236:
237: protected List getToolBarItems() {
238: return new ArrayList();
239: }
240:
241: private final FilterGUI getFilterGUI() {
242: if (theFilterGUI == null) {
243: theFilterGUI = createFilterGUI(theEventGenerator);
244: }
245: return theFilterGUI;
246: }
247:
248: protected abstract FilterGUI createFilterGUI(
249: EventGenerator anEventGenerator);
250:
251: protected void addToSchedule(Timed timed) {
252: synchronized (schedule) {
253: schedule.add(timed);
254: Object key = timed.getKey();
255: if (key != null)
256: map.put(key, timed);
257: scheduleChanged = true;
258: }
259: }
260:
261: protected void removeFromSchedule(Timed timed) {
262: synchronized (schedule) {
263: schedule.remove(timed);
264: Object key = timed.getKey();
265: if (key != null)
266: map.remove(key);
267: scheduleChanged = true;
268: }
269: }
270:
271: // protected final void resortSchedule(Timed timed) {
272: // synchronized (schedule) {
273: // schedule.remove(timed);
274: // schedule.add(timed);
275: // scheduleChanged = true;
276: // }
277: // }
278:
279: protected final void finishScheduleUpdate() {
280: synchronized (schedule) {
281: if (scheduleChanged) {
282: if (tableModel != null) {
283: tableModel.fireTableDataChanged();
284: }
285: scheduleChanged = false;
286: }
287: }
288: }
289:
290: protected boolean isAutoSend() {
291: return getGUI().isAutoSend();
292: }
293:
294: protected void setAutoSend(boolean newAutoSend) {
295: getGUI().setAutoSend(newAutoSend);
296: }
297:
298: protected boolean isAutoSendInvisible() {
299: return getGUI().isAutoSendInvisible();
300: }
301:
302: protected void setAutoSendInvisible(boolean newAutoSend) {
303: getGUI().setAutoSendInvisible(newAutoSend);
304: }
305:
306: public final void advanceTime() {
307: advanceTime(theEventGenerator.getExecutionTime());
308: }
309:
310: public final void advanceTime(long newExecutionTime) {
311: ArrayList expiredReports = new ArrayList();
312: synchronized (schedule) {
313: for (boolean done = false; !done;) {
314: done = true;
315: Collection headSet = new ArrayList(rawSchedule
316: .headSet(new Timed.Dummy(newExecutionTime + 1)));
317: for (Iterator reports = headSet.iterator(); reports
318: .hasNext();) {
319: Timed object = (Timed) reports.next();
320: if (isAutoSend() || object.isEnabled()) {
321: expiredReports.add(object);
322: }
323: }
324: if (expiredReports.size() > 0) {
325: for (Iterator reports = expiredReports.iterator(); reports
326: .hasNext();) {
327: Timed object = (Timed) reports.next();
328: removeFromSchedule(object); // Key may change invalidating sorted set.
329: boolean didExpire = object
330: .expired(newExecutionTime);
331: if (!didExpire) {
332: addToSchedule(object);
333: done = false; // May need to process this again
334: } else {
335: writeLog(object);
336: }
337: }
338: expiredReports.clear();
339: }
340: }
341: }
342: finishScheduleUpdate();
343: }
344:
345: // for readability
346: private static final char TAB = '\t';
347: private static final char QUOTE = '"';
348:
349: protected void writeLog(Timed timed) {
350: if (logWriter != null) {
351: StringBuffer buf = new StringBuffer();
352: ManagerTableModel model = getTableModel();
353: int[] columns = model.getLogColumns();
354: for (int i = 0; i < columns.length; i++) {
355: Object o = model.getValue(columns[i], timed);
356: String val = o == null ? "" : o.toString();
357: boolean needQuote = val.indexOf(TAB) >= 0;
358: if (i > 0)
359: buf.append(TAB);
360: if (needQuote)
361: buf.append(QUOTE);
362: buf.append(val);
363: if (needQuote)
364: buf.append(QUOTE);
365: }
366: logWriter.println(buf.toString());
367: }
368: }
369:
370: protected void writeLogHeader() {
371: if (logWriter != null) {
372: StringBuffer buf = new StringBuffer();
373: ManagerTableModel model = getTableModel();
374: int[] columns = model.getLogColumns();
375: for (int i = 0; i < columns.length; i++) {
376: String val = model.getColumnName(columns[i]);
377: boolean needQuote = val.indexOf(TAB) >= 0;
378: if (i > 0)
379: buf.append(TAB);
380: if (needQuote)
381: buf.append(QUOTE);
382: buf.append(val);
383: if (needQuote)
384: buf.append(QUOTE);
385: }
386: logWriter.println(buf.toString());
387: }
388: }
389:
390: public final ManagerTableModel getTableModel() {
391: if (tableModel == null) {
392: tableModel = createTableModel();
393: }
394: return tableModel;
395: }
396:
397: protected abstract ManagerTableModel createTableModel();
398:
399: protected final void postErrorMessage(String message) {
400: theEventGenerator.postErrorMessage(getGUI(), message);
401: }
402:
403: protected JButton getPluginButton() {
404: JButton pluginButton = new JButton("Plugins...");
405: pluginButton.setToolTipText("Select and configure plugins");
406: pluginButton.addActionListener(new ActionListener() {
407: public void actionPerformed(ActionEvent e) {
408: postPluginDialog();
409: }
410: });
411: return pluginButton;
412: }
413:
414: private static class PluginItem extends JCheckBox {
415: public Plugin thePlugin;
416:
417: public PluginItem(Plugin aPlugin) {
418: super (aPlugin.getPluginName());
419: thePlugin = aPlugin;
420: }
421: }
422:
423: protected Iterator getEnabledPlugins() {
424: final Iterator all = plugins.iterator();
425: return new Iterator() {
426: private PluginItem nextItem = null;
427:
428: public boolean hasNext() {
429: while (nextItem == null) {
430: if (!all.hasNext())
431: return false;
432: nextItem = (PluginItem) all.next();
433: if (nextItem.isSelected())
434: return true;
435: nextItem = null;
436: }
437: return false;
438: }
439:
440: public Object next() {
441: Object result = nextItem.thePlugin;
442: nextItem = null;
443: return result;
444: }
445:
446: public void remove() {
447: throw new UnsupportedOperationException(
448: "remove not supported");
449: }
450: };
451: }
452:
453: private void postPluginDialog() {
454: JPanel box = new JPanel(new GridBagLayout());
455: GridBagConstraints gbc = new GridBagConstraints();
456: for (int i = 0, n = plugins.size(); i < n; i++) {
457: PluginItem item = (PluginItem) plugins.get(i);
458: if (item.thePlugin.getClass() == getDefaultPluginClass()) {
459: item.disable();
460: }
461: gbc.gridy = i;
462: gbc.gridx = 0;
463: gbc.anchor = gbc.WEST;
464: box.add(item, gbc);
465: if (item.thePlugin.isConfigurable()) {
466: final Plugin thePlugin = item.thePlugin;
467: JButton configureButton = new JButton("Configure...");
468: configureButton.addActionListener(new ActionListener() {
469: public void actionPerformed(ActionEvent e) {
470: thePlugin.configure(getGUI());
471: }
472: });
473: gbc.gridx = 1;
474: box.add(configureButton, gbc);
475: }
476: }
477: OptionPane.showOptionDialog(getGUI(), box, "Select Plugins",
478: OptionPane.DEFAULT_OPTION, OptionPane.QUESTION_MESSAGE,
479: null, null, null);
480: firePluginChanged();
481: }
482:
483: protected void firePluginChanged() {
484: }
485:
486: protected void addPlugin(Plugin plugin, boolean disabled) {
487: PluginItem item = new PluginItem(plugin);
488: item.setSelected(!disabled);
489: plugins.add(item);
490: }
491:
492: protected static final int ANNOTATION_WIDTH = 120;
493:
494: protected abstract class ManagerTableModel extends EGTableModelBase
495: implements EGTableModel {
496: protected int[] logColumns; // Filled in by subclass
497:
498: private Timed[] rows = null;
499:
500: public int[] getLogColumns() {
501: if (logColumns == null)
502: logColumns = new int[0];
503: return logColumns;
504: }
505:
506: public int getRowCount() {
507: synchronized (schedule) {
508: if (rows == null) {
509: rows = (Timed[]) schedule
510: .toArray(new Timed[schedule.size()]);
511: }
512: return rows.length;
513: }
514: }
515:
516: public void fireTableDataChanged() {
517: synchronized (schedule) {
518: rows = null;
519: super .fireTableDataChanged();
520: }
521: }
522:
523: protected Timed getRowObject(int row) {
524: synchronized (schedule) {
525: if (rows == null)
526: return null;
527: if (row < rows.length) {
528: return rows[row];
529: }
530: }
531: return null;
532: }
533:
534: public final Object getValueAt(int row, int col) {
535: return getValue(col, getRowObject(row));
536: }
537:
538: public abstract Object getValue(int col, Object rowObject);
539: }
540: }
|