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 }