001: // $Id: Draw.java,v 1.33 2006/10/27 16:25:58 belaban Exp $
002:
003: package org.jgroups.demos;
004:
005: import org.jgroups.*;
006: import org.jgroups.debug.Debugger;
007: import org.jgroups.jmx.JmxConfigurator;
008: import org.jgroups.util.Util;
009:
010: import javax.management.MBeanServer;
011: import javax.swing.*;
012: import java.awt.*;
013: import java.awt.event.*;
014: import java.util.Random;
015:
016: /**
017: * Shared whiteboard, each new instance joins the same group. Each instance chooses a random color,
018: * mouse moves are broadcast to all group members, which then apply them to their canvas<p>
019: * @author Bela Ban, Oct 17 2001
020: */
021: public class Draw extends ExtendedReceiverAdapter implements
022: ActionListener, ChannelListener {
023: String groupname = "DrawGroupDemo";
024: private Channel channel = null;
025: private int member_size = 1;
026: Debugger debugger = null;
027: final boolean first = true;
028: final boolean cummulative = true;
029: private JFrame mainFrame = null;
030: private JPanel sub_panel = null;
031: private DrawPanel panel = null;
032: private JButton clear_button, leave_button;
033: private final Random random = new Random(System.currentTimeMillis());
034: private final Font default_font = new Font("Helvetica", Font.PLAIN,
035: 12);
036: private final Color draw_color = selectColor();
037: private final Color background_color = Color.white;
038: boolean no_channel = false;
039: boolean jmx;
040:
041: public Draw(String props, boolean debug, boolean cummulative,
042: boolean no_channel, boolean jmx) throws Exception {
043: this .no_channel = no_channel;
044: this .jmx = jmx;
045: if (no_channel)
046: return;
047:
048: channel = new JChannel(props);
049: // channel.setOpt(Channel.BLOCK, Boolean.TRUE);
050: if (debug) {
051: debugger = new Debugger((JChannel) channel, cummulative);
052: debugger.start();
053: }
054: channel.setOpt(Channel.AUTO_RECONNECT, Boolean.TRUE);
055: channel.setReceiver(this );
056: channel.addChannelListener(this );
057: }
058:
059: public Draw(Channel channel) throws Exception {
060: this .channel = channel;
061: channel.setOpt(Channel.AUTO_RECONNECT, Boolean.TRUE);
062: channel.setReceiver(this );
063: channel.addChannelListener(this );
064: }
065:
066: public String getGroupName() {
067: return groupname;
068: }
069:
070: public void setGroupName(String groupname) {
071: if (groupname != null)
072: this .groupname = groupname;
073: }
074:
075: public static void main(String[] args) {
076: Draw draw = null;
077: String props = null;
078: boolean debug = false;
079: boolean cummulative = false;
080: boolean no_channel = false;
081: boolean jmx = false;
082: String group_name = null;
083:
084: for (int i = 0; i < args.length; i++) {
085: if ("-help".equals(args[i])) {
086: help();
087: return;
088: }
089: if ("-debug".equals(args[i])) {
090: debug = true;
091: continue;
092: }
093: if ("-cummulative".equals(args[i])) {
094: cummulative = true;
095: continue;
096: }
097: if ("-props".equals(args[i])) {
098: props = args[++i];
099: continue;
100: }
101: if ("-no_channel".equals(args[i])) {
102: no_channel = true;
103: continue;
104: }
105: if ("-jmx".equals(args[i])) {
106: jmx = true;
107: continue;
108: }
109: if ("-groupname".equals(args[i])) {
110: group_name = args[++i];
111: continue;
112: }
113:
114: help();
115: return;
116: }
117:
118: if (props == null) {
119: props = "UDP(down_thread=false;mcast_send_buf_size=640000;mcast_port=45566;discard_incompatible_packets=true;"
120: + "ucast_recv_buf_size=20000000;mcast_addr=228.10.10.10;up_thread=false;loopback=false;"
121: + "mcast_recv_buf_size=25000000;max_bundle_size=64000;max_bundle_timeout=30;"
122: + "use_incoming_packet_handler=true;use_outgoing_packet_handler=false;"
123: + "ucast_send_buf_size=640000;tos=16;enable_bundling=true;ip_ttl=2):"
124: + "PING(timeout=2000;down_thread=false;num_initial_members=3;up_thread=false):"
125: + "MERGE2(max_interval=10000;down_thread=false;min_interval=5000;up_thread=false):"
126: + "FD(timeout=2000;max_tries=3;down_thread=false;up_thread=false):"
127: + "VERIFY_SUSPECT(timeout=1500;down_thread=false;up_thread=false):"
128: + "pbcast.NAKACK(max_xmit_size=60000;down_thread=false;use_mcast_xmit=false;gc_lag=0;"
129: + "discard_delivered_msgs=true;up_thread=false;retransmit_timeout=100,200,300,600,1200,2400,4800):"
130: + "UNICAST(timeout=300,600,1200,2400,3600;down_thread=false;up_thread=false):"
131: + "pbcast.STABLE(stability_delay=1000;desired_avg_gossip=50000;max_bytes=400000;down_thread=false;"
132: + "up_thread=false):"
133: + "VIEW_SYNC(down_thread=false;avg_send_interval=60000;up_thread=false):"
134: + "pbcast.GMS(print_local_addr=true;join_timeout=3000;down_thread=false;"
135: + "join_retry_timeout=2000;up_thread=false;shun=true):"
136: + "FC(max_credits=2000000;down_thread=false;up_thread=false;min_threshold=0.10):"
137: + "FRAG2(frag_size=60000;down_thread=false;up_thread=false):"
138: + "pbcast.STATE_TRANSFER(down_thread=false;up_thread=false)";
139: }
140:
141: try {
142: draw = new Draw(props, debug, cummulative, no_channel, jmx);
143: if (group_name != null)
144: draw.setGroupName(group_name);
145: draw.go();
146: } catch (Throwable e) {
147: e.printStackTrace();
148: System.exit(0);
149: }
150: }
151:
152: static void help() {
153: System.out
154: .println("\nDraw [-help] [-debug] [-cummulative] [-no_channel] [-props <protocol stack definition>]"
155: + " [-groupname <name>]");
156: System.out.println("-debug: brings up a visual debugger");
157: System.out
158: .println("-no_channel: doesn't use JGroups at all, any drawing will be relected on the "
159: + "whiteboard directly");
160: System.out
161: .println("-props: argument can be an old-style protocol stack specification, or it can be "
162: + "a URL. In the latter case, the protocol specification will be read from the URL\n");
163: }
164:
165: private Color selectColor() {
166: int red = (Math.abs(random.nextInt()) % 255);
167: int green = (Math.abs(random.nextInt()) % 255);
168: int blue = (Math.abs(random.nextInt()) % 255);
169: return new Color(red, green, blue);
170: }
171:
172: public void go() throws Exception {
173: if (!no_channel) {
174: channel.connect(groupname);
175: if (jmx) {
176: MBeanServer server = Util.getMBeanServer();
177: if (server == null)
178: throw new Exception(
179: "No MBeanServers found;"
180: + "\nDraw needs to be run with an MBeanServer present, or inside JDK 5");
181: JmxConfigurator.registerChannel((JChannel) channel,
182: server, "jgroups", channel.getClusterName(),
183: true);
184: }
185: }
186: mainFrame = new JFrame();
187: mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
188: panel = new DrawPanel();
189: panel.setBackground(background_color);
190: sub_panel = new JPanel();
191: mainFrame.getContentPane().add("Center", panel);
192: clear_button = new JButton("Clear");
193: clear_button.setFont(default_font);
194: clear_button.addActionListener(this );
195: leave_button = new JButton("Leave");
196: leave_button.setFont(default_font);
197: leave_button.addActionListener(this );
198: sub_panel.add("South", clear_button);
199: sub_panel.add("South", leave_button);
200: mainFrame.getContentPane().add("South", sub_panel);
201: mainFrame.setBackground(background_color);
202: clear_button.setForeground(Color.blue);
203: leave_button.setForeground(Color.blue);
204: setTitle();
205: mainFrame.pack();
206: mainFrame.setLocation(15, 25);
207: mainFrame.setBounds(new Rectangle(250, 250));
208: mainFrame.setVisible(true);
209: }
210:
211: void setTitle(String title) {
212: String tmp = "";
213: if (no_channel) {
214: mainFrame.setTitle(" Draw Demo ");
215: return;
216: }
217: if (title != null) {
218: mainFrame.setTitle(title);
219: } else {
220: if (channel.getLocalAddress() != null)
221: tmp += channel.getLocalAddress();
222: tmp += " (" + member_size + ")";
223: mainFrame.setTitle(tmp);
224: }
225: }
226:
227: void setTitle() {
228: setTitle(null);
229: }
230:
231: public void receive(Message msg) {
232: byte[] buf = msg.getRawBuffer();
233: if (buf == null) {
234: System.err.println("received null buffer from "
235: + msg.getSrc() + ", headers: " + msg.getHeaders());
236: return;
237: }
238:
239: try {
240: DrawCommand comm = (DrawCommand) Util
241: .streamableFromByteBuffer(DrawCommand.class, buf,
242: msg.getOffset(), msg.getLength());
243: switch (comm.mode) {
244: case DrawCommand.DRAW:
245: if (panel != null)
246: panel.drawPoint(comm);
247: break;
248: case DrawCommand.CLEAR:
249: clearPanel();
250: break;
251: default:
252: System.err
253: .println("***** received invalid draw command "
254: + comm.mode);
255: break;
256: }
257: } catch (Exception e) {
258: e.printStackTrace();
259: }
260: }
261:
262: public void viewAccepted(View v) {
263: if (v instanceof MergeView)
264: System.out.println("** MergeView=" + v);
265: else
266: System.out.println("** View=" + v);
267: member_size = v.size();
268: if (mainFrame != null)
269: setTitle();
270: }
271:
272: public void block() {
273: System.out.println("-- received BlockEvent");
274: }
275:
276: public void unblock() {
277: System.out.println("-- received UnblockEvent");
278: }
279:
280: /* --------------- Callbacks --------------- */
281:
282: public void clearPanel() {
283: if (panel != null)
284: panel.clear();
285: }
286:
287: public void sendClearPanelMsg() {
288: int tmp[] = new int[1];
289: tmp[0] = 0;
290: DrawCommand comm = new DrawCommand(DrawCommand.CLEAR);
291:
292: try {
293: byte[] buf = Util.streamableToByteBuffer(comm);
294: channel.send(new Message(null, null, buf));
295: } catch (Exception ex) {
296: System.err.println(ex);
297: }
298: }
299:
300: public void actionPerformed(ActionEvent e) {
301: String command = e.getActionCommand();
302: if ("Clear".equals(command)) {
303: if (no_channel) {
304: clearPanel();
305: return;
306: }
307: sendClearPanelMsg();
308: } else if ("Leave".equals(command)) {
309: stop();
310: } else
311: System.out.println("Unknown action");
312: }
313:
314: public void stop() {
315: if (!no_channel) {
316: try {
317: channel.close();
318: } catch (Exception ex) {
319: System.err.println(ex);
320: }
321: }
322: mainFrame.setVisible(false);
323: mainFrame.dispose();
324: }
325:
326: /* ------------------------------ ChannelListener interface -------------------------- */
327:
328: public void channelConnected(Channel channel) {
329:
330: }
331:
332: public void channelDisconnected(Channel channel) {
333:
334: }
335:
336: public void channelClosed(Channel channel) {
337:
338: }
339:
340: public void channelShunned() {
341: System.out
342: .println("-- received EXIT, waiting for ChannelReconnected callback");
343: setTitle(" Draw Demo - shunned ");
344: }
345:
346: public void channelReconnected(Address addr) {
347: setTitle();
348: }
349:
350: /* --------------------------- End of ChannelListener interface ---------------------- */
351:
352: private class DrawPanel extends JPanel implements
353: MouseMotionListener {
354: final Dimension preferred_size = new Dimension(235, 170);
355: Image img = null; // for drawing pixels
356: Dimension d, imgsize = null;
357: Graphics gr = null;
358:
359: public DrawPanel() {
360: createOffscreenImage();
361: addMouseMotionListener(this );
362: addComponentListener(new ComponentAdapter() {
363: public void componentResized(ComponentEvent e) {
364: if (getWidth() <= 0 || getHeight() <= 0)
365: return;
366: createOffscreenImage();
367: }
368: });
369: }
370:
371: final void createOffscreenImage() {
372: d = getSize();
373: if (img == null || imgsize == null
374: || imgsize.width != d.width
375: || imgsize.height != d.height) {
376: img = createImage(d.width, d.height);
377: if (img != null)
378: gr = img.getGraphics();
379: imgsize = d;
380: }
381: }
382:
383: /* ---------------------- MouseMotionListener interface------------------------- */
384:
385: public void mouseMoved(MouseEvent e) {
386: }
387:
388: public void mouseDragged(MouseEvent e) {
389: int x = e.getX(), y = e.getY();
390: DrawCommand comm = new DrawCommand(DrawCommand.DRAW, x, y,
391: draw_color.getRed(), draw_color.getGreen(),
392: draw_color.getBlue());
393:
394: if (no_channel) {
395: drawPoint(comm);
396: return;
397: }
398:
399: try {
400: byte[] buf = Util.streamableToByteBuffer(comm);
401: channel.send(new Message(null, null, buf));
402: Thread.yield(); // gives the repainter some breath
403: } catch (Exception ex) {
404: System.err.println(ex);
405: }
406: }
407:
408: /* ------------------- End of MouseMotionListener interface --------------------- */
409:
410: /**
411: * Adds pixel to queue and calls repaint() whenever we have MAX_ITEMS pixels in the queue
412: * or when MAX_TIME msecs have elapsed (whichever comes first). The advantage compared to just calling
413: * repaint() after adding a pixel to the queue is that repaint() can most often draw multiple points
414: * at the same time.
415: */
416: public void drawPoint(DrawCommand c) {
417: if (c == null || gr == null)
418: return;
419: gr.setColor(new Color(c.r, c.g, c.b));
420: gr.fillOval(c.x, c.y, 10, 10);
421: repaint();
422: }
423:
424: public void clear() {
425: if (gr == null)
426: return;
427: gr.clearRect(0, 0, getSize().width, getSize().height);
428: repaint();
429: }
430:
431: public Dimension getPreferredSize() {
432: return preferred_size;
433: }
434:
435: public void paintComponent(Graphics g) {
436: super .paintComponent(g);
437: if (img != null) {
438: g.drawImage(img, 0, 0, null);
439: }
440: }
441:
442: }
443:
444: }
|