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: package org.cougaar.mts.std;
028:
029: import java.awt.Container;
030: import java.awt.Dimension;
031: import java.awt.event.ActionEvent;
032: import java.awt.event.ActionListener;
033: import java.awt.event.WindowAdapter;
034: import java.awt.event.WindowEvent;
035: import java.util.HashMap;
036: import java.util.Iterator;
037:
038: import javax.swing.BoxLayout;
039: import javax.swing.JButton;
040: import javax.swing.JCheckBox;
041: import javax.swing.JComponent;
042: import javax.swing.JFrame;
043: import javax.swing.JPanel;
044: import javax.swing.JScrollPane;
045: import javax.swing.JSplitPane;
046: import javax.swing.JTextArea;
047: import javax.swing.ScrollPaneConstants;
048: import javax.swing.SwingUtilities;
049: import javax.swing.border.TitledBorder;
050:
051: import org.cougaar.core.component.ServiceBroker;
052: import org.cougaar.core.component.ServiceProvider;
053: import org.cougaar.core.mts.MessageAddress;
054: import org.cougaar.core.service.ThreadService;
055: import org.cougaar.mts.base.DestinationQueue;
056: import org.cougaar.mts.base.DestinationQueueDelegateImplBase;
057: import org.cougaar.mts.base.StandardAspect;
058:
059: /**
060: * This Aspect includes the ServiceProvider for and implementation of
061: * the {@link StepService}, as well as a use of that service in a
062: * Swing gui.
063: */
064: public final class StepperAspect extends StandardAspect {
065:
066: private StepFrame frame;
067: private HashMap controllers;
068: private ThreadService threadService;
069: private StepService service;
070:
071: private ThreadService threadService() {
072: if (threadService != null)
073: return threadService;
074: ServiceBroker sb = getServiceBroker();
075: threadService = (ThreadService) sb.getService(this ,
076: ThreadService.class, null);
077: return threadService;
078: }
079:
080: public Object getDelegate(Object delegatee, Class type) {
081: if (type == DestinationQueue.class) {
082: return new DestinationQueueDelegate(
083: (DestinationQueue) delegatee);
084: } else {
085: return null;
086: }
087: }
088:
089: private StepFrame ensureFrame() {
090: synchronized (this ) {
091: if (frame == null) {
092: frame = new StepFrame(getRegistry().getIdentifier());
093: if (controllers == null) {
094: controllers = new HashMap();
095: } else {
096: Iterator i = controllers.values().iterator();
097: while (i.hasNext()) {
098: StepController controller = (StepController) i
099: .next();
100: frame.addControllerWidget(controller);
101: }
102: }
103: }
104: }
105: if (!frame.isVisible())
106: frame.setVisible(true);
107: return frame;
108: }
109:
110: public void load() {
111: super .load();
112: service = new ServiceImpl();
113: ServiceBroker sb = getServiceBroker();
114: sb.addService(StepService.class, new StepServiceProvider());
115: }
116:
117: private synchronized void frameClosing() {
118: service.stepAll();
119: frame.dispose();
120: frame = null;
121: }
122:
123: private synchronized void addController(StepController controller,
124: MessageAddress address) {
125: controllers.put(address, controller);
126: }
127:
128: private class ServiceImpl implements StepService {
129: public void pause(MessageAddress destination) {
130: StepController controller = (StepController) controllers
131: .get(destination);
132: if (controller != null)
133: controller.pause();
134: }
135:
136: public void resume(MessageAddress destination) {
137: StepController controller = (StepController) controllers
138: .get(destination);
139: if (controller != null)
140: controller.resume();
141: }
142:
143: public void step(MessageAddress destination) {
144: StepController controller = (StepController) controllers
145: .get(destination);
146: if (controller != null)
147: controller.step();
148: }
149:
150: public synchronized void pauseAll() {
151: Iterator i = controllers.values().iterator();
152: while (i.hasNext()) {
153: StepController controller = (StepController) i.next();
154: controller.pause();
155: }
156: }
157:
158: public synchronized void resumeAll() {
159: Iterator i = controllers.values().iterator();
160: while (i.hasNext()) {
161: StepController controller = (StepController) i.next();
162: controller.resume();
163: }
164: }
165:
166: public synchronized void stepAll() {
167: Iterator i = controllers.values().iterator();
168: while (i.hasNext()) {
169: StepController controller = (StepController) i.next();
170: controller.step();
171: }
172: }
173: }
174:
175: private class StepServiceProvider implements ServiceProvider {
176: public Object getService(ServiceBroker sb, Object client,
177: Class serviceClass) {
178: if (serviceClass == StepService.class) {
179: return service;
180: } else {
181: return null;
182: }
183: }
184:
185: public void releaseService(ServiceBroker sb, Object client,
186: Class serviceClass, Object service) {
187: }
188:
189: }
190:
191: private class StepFrame extends JFrame implements
192: ScrollPaneConstants {
193: private JComponent contents, controllers, scroller;
194:
195: private StepFrame(String id) {
196: super ("Outgoing messages from " + id);
197:
198: JPanel buttons = new JPanel();
199: buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS));
200:
201: JButton pauseAll = new JButton("Pause All");
202: pauseAll.addActionListener(new ActionListener() {
203: public void actionPerformed(ActionEvent e) {
204: service.pauseAll();
205: }
206: });
207: buttons.add(pauseAll);
208:
209: JButton resumeAll = new JButton("Resume All");
210: resumeAll.addActionListener(new ActionListener() {
211: public void actionPerformed(ActionEvent e) {
212: service.resumeAll();
213: }
214: });
215: buttons.add(resumeAll);
216:
217: JButton stepAll = new JButton("Step All");
218: stepAll.addActionListener(new ActionListener() {
219: public void actionPerformed(ActionEvent e) {
220: service.stepAll();
221: }
222: });
223: buttons.add(stepAll);
224:
225: contents = new JPanel();
226: contents
227: .setLayout(new BoxLayout(contents, BoxLayout.Y_AXIS));
228:
229: Container cp = getContentPane();
230: cp.setLayout(new BoxLayout(cp, BoxLayout.Y_AXIS));
231: cp.add(buttons);
232: cp.add(contents);
233:
234: addWindowListener(new WindowAdapter() {
235: public void windowClosing(WindowEvent e) {
236: frameClosing();
237: }
238: });
239:
240: setSize(350, 480);
241: setLocation(300, 300);
242: }
243:
244: private void addWidget(final StepController component,
245: final MessageAddress address) {
246: SwingUtilities.invokeLater(new Runnable() {
247: public void run() {
248: addController(component, address);
249: addControllerWidget(component);
250: }
251: });
252: }
253:
254: private void addControllerWidget(StepController component) {
255: if (controllers != null) {
256: controllers = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
257: controllers, component);
258: contents.remove(scroller);
259: } else {
260: controllers = component;
261: }
262: scroller = new JScrollPane(controllers,
263: VERTICAL_SCROLLBAR_AS_NEEDED,
264: HORIZONTAL_SCROLLBAR_NEVER);
265: contents.add(scroller);
266: contents.revalidate();
267: }
268:
269: }
270:
271: private static class StepController extends JPanel implements
272: ScrollPaneConstants {
273: private DestinationQueueDelegate delegate;
274: private JButton send;
275: private JCheckBox pause;
276: private JTextArea messageWindow;
277: private MessageAddress destination;
278: private int count;
279:
280: private StepController(DestinationQueueDelegate delegate,
281: MessageAddress destination) {
282: count = 0;
283: this .delegate = delegate;
284: this .destination = destination;
285:
286: setLayout(new BoxLayout(this , BoxLayout.Y_AXIS));
287:
288: JPanel buttons = new JPanel();
289: buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS));
290:
291: pause = new JCheckBox("Pause");
292: pause.addActionListener(new ActionListener() {
293: public void actionPerformed(ActionEvent e) {
294: boolean mode = pause.isSelected();
295: StepController.this .delegate.setStepping(mode);
296: }
297: });
298: pause.setSelected(delegate.isStepping());
299:
300: send = new JButton("Send");
301: send.addActionListener(new ActionListener() {
302: public void actionPerformed(ActionEvent e) {
303: StepController.this .delegate.step();
304: }
305: });
306: send.setEnabled(false);
307:
308: buttons.add(pause);
309: buttons.add(send);
310:
311: messageWindow = new JTextArea();
312: messageWindow.setEditable(false);
313: messageWindow.setLineWrap(true);
314:
315: this .add(buttons);
316: this .add(new JScrollPane(messageWindow,
317: VERTICAL_SCROLLBAR_ALWAYS,
318: HORIZONTAL_SCROLLBAR_NEVER));
319:
320: setBorder(new TitledBorder("Messages to " + destination));
321: Dimension size = new Dimension(300, 100);
322: // setMaximumSize(size);
323: // setMinimumSize(size);
324: setPreferredSize(size);
325:
326: }
327:
328: private void pause() {
329: if (!pause.isSelected()) {
330: pause.setSelected(true);
331: delegate.setStepping(true);
332: }
333: }
334:
335: private void resume() {
336: if (pause.isSelected()) {
337: pause.setSelected(false);
338: delegate.setStepping(false);
339: }
340: }
341:
342: private void step() {
343: delegate.step();
344: }
345:
346: // Should these use SwingUtilities,invokeLater?
347: private void messageWait(final AttributedMessage msg) {
348: send.setEnabled(true);
349: StringBuffer buf = new StringBuffer();
350: buf.append(msg.logString());
351: buf.append("\nAttributes: ");
352: buf.append(msg.getAttributesAsString());
353: buf.append("\nBody: ");
354: buf.append(msg.getRawMessage().toString());
355: messageWindow.setText(buf.toString());
356: }
357:
358: private void increment() {
359: setBorder(new TitledBorder(Integer.toString(++count)
360: + " messages to " + destination));
361: }
362:
363: private void clearMessage() {
364: send.setEnabled(false);
365: messageWindow.setText("");
366: }
367:
368: }
369:
370: private class DestinationQueueDelegate extends
371: DestinationQueueDelegateImplBase {
372:
373: private StepController widget;
374: private boolean stepping;
375: private Object lock = new Object();
376: private Runnable oneStep;
377:
378: private DestinationQueueDelegate(DestinationQueue delegatee) {
379: super (delegatee);
380: oneStep = new OneStep();
381: }
382:
383: private boolean isStepping() {
384: return stepping;
385: }
386:
387: private void setStepping(boolean mode) {
388: stepping = mode;
389: if (!stepping)
390: step();
391: }
392:
393: private class OneStep implements Runnable {
394: public void run() {
395: lockStep();
396: }
397: }
398:
399: // Should probably happen in its own Thread so it doesn't
400: // block Swing.
401: private void step() {
402: // lockStep();
403: threadService().getThread(this , oneStep).start();
404: }
405:
406: private void lockStep() {
407: synchronized (lock) {
408: lock.notify();
409: }
410: }
411:
412: private void ensureWidget(MessageAddress address) {
413: StepFrame frame = ensureFrame();
414: if (widget == null) {
415: widget = new StepController(this , address);
416: frame.addWidget(widget, address);
417: }
418: }
419:
420: public void dispatchNextMessage(AttributedMessage msg) {
421: ensureWidget(msg.getTarget());
422: widget.increment();
423: if (!stepping) {
424: super .dispatchNextMessage(msg);
425: } else {
426: synchronized (lock) {
427: widget.messageWait(msg);
428: // We're now locking up one of the available
429: // Threads!
430: try {
431: lock.wait();
432: } catch (InterruptedException ex) {
433: }
434: }
435: super.dispatchNextMessage(msg);
436: widget.clearMessage();
437: }
438: }
439:
440: }
441:
442: }
|