001 /******************************************************************************
002 * Copyright (C) MActor Developers. All rights reserved. *
003 * ---------------------------------------------------------------------------*
004 * This file is part of MActor. *
005 * *
006 * MActor is free software; you can redistribute it and/or modify *
007 * it under the terms of the GNU General Public License as published by *
008 * the Free Software Foundation; either version 2 of the License, or *
009 * (at your option) any later version. *
010 * *
011 * MActor is distributed in the hope that it will be useful, *
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
014 * GNU General Public License for more details. *
015 * *
016 * You should have received a copy of the GNU General Public License *
017 * along with MActor; if not, write to the Free Software *
018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
019 ******************************************************************************/
020 package org.mactor.ui.gui.testrunner;
021
022 import java.awt.BorderLayout;
023 import java.awt.Color;
024 import java.awt.FlowLayout;
025 import java.awt.event.ActionEvent;
026 import java.awt.event.ActionListener;
027 import java.io.File;
028
029 import javax.swing.AbstractAction;
030 import javax.swing.JButton;
031 import javax.swing.JLabel;
032 import javax.swing.JPanel;
033 import javax.swing.JScrollPane;
034 import javax.swing.JSplitPane;
035 import javax.swing.JTextArea;
036 import javax.swing.SwingUtilities;
037 import javax.swing.Timer;
038
039 import org.mactor.brokers.Message;
040 import org.mactor.brokers.MessageBrokerManager;
041 import org.mactor.brokers.MessageSubscriber;
042 import org.mactor.extensions.GreedyMessageSelector;
043 import org.mactor.framework.MactorException;
044 import org.mactor.ui.gui.GuiUtil;
045 import org.mactor.ui.gui.ResourceUtil;
046 import org.mactor.ui.gui.Stoppable;
047
048 public class ChannelRuntimePanel extends JPanel implements Stoppable {
049 String channel;
050 Object lock = new Object();
051 Object pendingMessageLock = new Object();
052 boolean requiresResponse;
053 boolean pendingResponse = false;
054 Message pendingResponseMessage;
055 JTextArea messageText = new JTextArea(20, 40);
056 ChannelMessageLogPanel cmlPanel;
057 Timer timer = new Timer(1000, new ActionListener() {
058 public void actionPerformed(ActionEvent e) {
059 if (sendButton.getBackground().equals(Color.RED))
060 sendButton.setBackground(subscribeButton.getBackground());
061 else
062 sendButton.setBackground(Color.RED);
063 }
064 });
065 private boolean busy = false;
066 private Object busyLock = new Object();
067 MessageSubscriber ms = new MessageSubscriber() {
068 public org.mactor.brokers.Message onMessage(final Message message) {
069 if (requiresResponse)
070 return handleIncomingWithResponse(message);
071 return null;
072 };
073 };
074 JButton subscribeButton = new JButton(new AbstractAction("Start Subscriber") {
075 public void actionPerformed(java.awt.event.ActionEvent e) {
076 try {
077 MessageBrokerManager.getInstance().subscribe(channel, ms, new GreedyMessageSelector());
078 subscribeButton.setEnabled(false);
079 unsubscribeButton.setEnabled(true);
080 sendButton.setEnabled(false);
081 } catch (MactorException me) {
082 GuiUtil.showGuiError(ChannelRuntimePanel.this, me);
083 }
084 };
085 });
086 JButton unsubscribeButton = new JButton(new AbstractAction("Stop Subscriber") {
087 public void actionPerformed(java.awt.event.ActionEvent e) {
088 try {
089 MessageBrokerManager.getInstance().unsubscribe(channel, ms);
090 timer.stop();
091 sendButton.setBackground(subscribeButton.getBackground());
092 subscribeButton.setEnabled(true);
093 unsubscribeButton.setEnabled(false);
094 sendButton.setEnabled(true);
095 } catch (MactorException me) {
096 GuiUtil.showGuiError(ChannelRuntimePanel.this, me);
097 }
098 };
099 });
100 JButton sendButton = new JButton(new AbstractAction("Publish Message") {
101 public void actionPerformed(java.awt.event.ActionEvent e) {
102 try {
103 if (pendingResponse) {
104 pendingResponseMessage = Message.createMessage(messageText.getText());
105 synchronized (pendingMessageLock) {
106 pendingMessageLock.notifyAll();
107 }
108 } else {
109 /*
110 * if(!subscribeButton.isEnabled()) {
111 * GuiUtil.showInfo(ChannelRuntimePanel.this, "Sorry, it is
112 * not possible to subscribe and published to the same
113 * channel in the same 'tab' \n(only response messages can
114 * be published )"); return; }
115 */
116 final Message outgoingMessage = Message.createMessage(messageText.getText());
117 sendButton.setEnabled(false);
118 new Thread(new Runnable() {
119 public void run() {
120 try {
121 MessageBrokerManager.getInstance().publish(channel, outgoingMessage);
122 SwingUtilities.invokeLater(new Runnable() {
123 public void run() {
124 sendButton.setEnabled(true);
125 }
126 });
127 } catch (final MactorException me) {
128 SwingUtilities.invokeLater(new Runnable() {
129 public void run() {
130 sendButton.setEnabled(true);
131 GuiUtil.showGuiError(ChannelRuntimePanel.this, me);
132 }
133 });
134 }
135 };
136 }).start();
137 }
138 } catch (MactorException me) {
139 GuiUtil.showGuiError(ChannelRuntimePanel.this, me);
140 }
141 };
142 });
143 JButton clearButton = new JButton(new AbstractAction("Clear") {
144 public void actionPerformed(java.awt.event.ActionEvent e) {
145 messageText.setText("");
146 };
147 });
148 private Message handleIncomingWithResponse(final Message message) {
149 try {
150 synchronized (busyLock) {
151 if (busy)
152 busyLock.wait();
153 busy = true;
154 }
155 } catch (InterruptedException ie) {
156 }
157 pendingResponse = true;
158 SwingUtilities.invokeLater(new Runnable() {
159 public void run() {
160 sendButton.setEnabled(true);
161 timer.start();
162 }
163 });
164 try {
165 synchronized (pendingMessageLock) {
166 pendingMessageLock.wait();
167 }
168 } catch (InterruptedException ie) {
169 }
170 pendingResponse = false;
171 final Message response = pendingResponseMessage;
172 response.getMessageContextInfo().setResponseToMessage(message);
173 SwingUtilities.invokeLater(new Runnable() {
174 public void run() {
175 timer.stop();
176 sendButton.setBackground(subscribeButton.getBackground());
177 synchronized (busyLock) {
178 busy = false;
179 busyLock.notify();
180 }
181 }
182 });
183 return response;
184 }
185 public void stop() {
186 try {
187 MessageBrokerManager.getInstance().unsubscribe(channel, ms);
188 } catch (MactorException me) {
189 me.printStackTrace();
190 }
191 }
192 public ChannelRuntimePanel(String channel, boolean requiresResponse) throws MactorException {
193 super(new BorderLayout());
194 this.channel = channel;
195 cmlPanel = new ChannelMessageLogPanel(channel);
196 this.requiresResponse = requiresResponse;
197 unsubscribeButton.setEnabled(false);
198 JPanel topPanel = new JPanel(new FlowLayout());
199 topPanel.add(subscribeButton);
200 topPanel.add(unsubscribeButton);
201 JPanel messagePanel = new JPanel(new BorderLayout());
202 messagePanel.add(new JLabel("Message:"), BorderLayout.NORTH);
203 messagePanel.add(new JScrollPane(messageText), BorderLayout.CENTER);
204 JPanel messageButtonPanel = new JPanel(new FlowLayout());
205 messageButtonPanel.add(sendButton);
206 messageButtonPanel.add(clearButton);
207 messagePanel.add(messageButtonPanel, BorderLayout.SOUTH);
208 JPanel logPanel = new JPanel(new BorderLayout());
209 logPanel.add(new JLabel("Message Log:"), BorderLayout.NORTH);
210 logPanel.add(cmlPanel, BorderLayout.CENTER);
211 JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, logPanel, messagePanel);
212 splitPane.setDividerLocation(400);
213 add(topPanel, BorderLayout.NORTH);
214 add(splitPane, BorderLayout.CENTER);
215 cmlPanel.setMessageSelectionChangedListener(new ChannelMessageLogPanel.MessageSelectionChangedListener() {
216 public void onChange(File archivedFile) {
217 try {
218 messageText.setText(ResourceUtil.readFileContent(archivedFile));
219 } catch (Exception e) {
220 e.printStackTrace();
221 }
222 }
223 });
224 }
225 }