Biblioteca Java - Blame information for rev 6

Subversion Repositories:
Rev:
Rev Author Line No. Line
6 mihai 1 /*
2  * To change this template, choose Tools | Templates
3  * and open the template in the editor.
4  */
5  
6 package mqdemo;
7  
8 /*
9  * @(#)QBrowser.java    1.7 09/15/04
10  *
11  * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved
12  * SUN PROPRIETARY/CONFIDENTIAL
13  * Use is subject to license terms.
14  *
15  */
16  
17 import java.awt.*;
18 import java.util.*;
19 import java.text.*;
20 import java.awt.event.*;
21 import javax.swing.*;
22 import javax.swing.event.*;
23 import javax.swing.table.*;
24  
25 import javax.jms.ConnectionFactory;
26 import javax.jms.Connection;
27 import javax.jms.Session;
28 import javax.jms.Destination;
29 import javax.jms.Queue;
30 import javax.jms.Topic;
31 import javax.jms.MessageConsumer;
32 import javax.jms.Message;
33 import javax.jms.QueueBrowser;
34 import javax.jms.DeliveryMode;
35 import javax.jms.StreamMessage;
36 import javax.jms.MapMessage;
37 import javax.jms.ObjectMessage;
38 import javax.jms.BytesMessage;
39 import javax.jms.TextMessage;
40 import javax.jms.JMSException;
41  
42  
43 /**
44  * The QBrowser example is a GUI application that lets you visually
45  * examine the contents of a JMS Queue. It is written using javax.swing.
46  *
47  * By default QBrowser will connect to the imqbrokerd running
48  * on localhost:7676. You can use the -b and -p options to change
49  * the host and port:
50  *
51  *     java QBrowser -b myserver -p7677
52  *
53  * Once QBrowser is up, enter the name of a queue and click Browse.
54  * A list of messages on the queue will appear in the main window.
55  * Select a message and click "Details" to see the contents of the message.
56  *
57  * QBrowser consists of the following classes:
58  *
59  * QBrowser      main(), the base GUI frame, and the JMS code
60  * MsgTable      A TableModel for handling the display of messages on a queue
61  * PropertyPanel A JPanel with a scrolling text area for displaying
62  *               simple text, or the contents of a HashMap.
63  * A number of minor event handling classes.
64  *
65  */
66 public class QBrowser extends JPanel implements javax.jms.MessageListener {
67  
68     JMenuItem       exit_item = null;
69     JLabel          qLabel = null;
70     JComboBox       qBox = null;
71     JButton         qBrowse = null;
72     JTable          msgTable = null;
73     JLabel          footerLabel = null;
74     JPanel          footerPanel = null;
75     QueueBrowser    qb = null;
76     Session         session  = null;
77     Connection      connection  = null;
78     Topic metricTopic = null;
79     MessageConsumer metricSubscriber = null;
80     JFrame          detailsFrame = null;
81     PropertyPanel headerPanel = null, propertyPanel = null, bodyPanel = null;
82  
83     static final String DEFAULT_BROKER_HOST = "localhost";
84     static final int    DEFAULT_BROKER_PORT = 7676;
85     static final String DEST_LIST_TOPIC_NAME = "mq.metrics.destination_list";
86     public static String version = "1.0";
87     public static String title = "QBrowser " + version;
88  
89     public static String serverHost = DEFAULT_BROKER_HOST;
90     public static int    serverPort = DEFAULT_BROKER_PORT;
91     public static String[] pad = {"", "0", "00", "000", "0000"};
92  
93     QBrowser() {
94         super(true);
95  
96         setBorder(BorderFactory.createEtchedBorder());
97         setLayout(new BorderLayout());
98  
99         // Create menu bar
100         JMenuBar  menubar = new JMenuBar();
101         JMenu menu = new JMenu("File");
102         exit_item = new JMenuItem("Exit");
103         exit_item.addActionListener(new ExitListener());
104         menu.add(exit_item);
105         menubar.add(menu);
106  
107         // Create panel to hold input area for Q name and Browse button
108         JPanel qPanel = new JPanel();
109         qPanel.setLayout(new BorderLayout());
110         qPanel.add(BorderLayout.NORTH, menubar);
111  
112         qLabel = new JLabel("Queue Name: ");
113         qPanel.add(BorderLayout.WEST, qLabel);
114  
115         qBox = new JComboBox();
116         Dimension d = qBox.getPreferredSize();
117         d.setSize(10 * d.getWidth(), d.getHeight());
118         qBox.setPreferredSize(d);
119         qBox.setEditable(true);
120         //qBox.addActionListener(new BrowseListener());
121         qPanel.add(BorderLayout.CENTER, qBox);
122         qBrowse = new JButton("Browse");
123         qBrowse.addActionListener(new BrowseListener() );
124         qPanel.add(BorderLayout.EAST, qBrowse);
125  
126         qPanel.updateUI();
127         //qPanel.setBackground(Color.YELLOW);
128  
129         add(BorderLayout.NORTH, qPanel);
130  
131         // Create panel to hold table of messages
132         JPanel tPanel = new JPanel();
133         tPanel.setLayout(new BorderLayout());
134  
135         msgTable = new JTable(new MsgTable());
136         msgTable.addMouseListener(new TableMouseListener());
137  
138         TableColumn column = msgTable.getColumnModel().getColumn(1);
139         column.setPreferredWidth(190);
140         column = msgTable.getColumnModel().getColumn(2);
141         column.setPreferredWidth(130);
142  
143         JScrollPane tablePane = new JScrollPane(msgTable);
144         tablePane.setPreferredSize(new Dimension(100, 300));
145         //tablePane.setMinimumSize(new Dimension(100, 100));
146         tPanel.add(BorderLayout.CENTER, tablePane);
147  
148         add(BorderLayout.CENTER, tPanel);
149  
150         // Create footer
151         footerPanel = new JPanel();
152         footerPanel.setLayout(new BorderLayout());
153         footerLabel = new JLabel("");
154         footerPanel.add(BorderLayout.WEST, footerLabel);
155  
156         JButton details = new JButton("Details...");
157         details.addActionListener(new DetailsListener() );
158         footerPanel.add(BorderLayout.EAST, details);
159  
160         add(BorderLayout.SOUTH, footerPanel);
161  
162         setFooter("Enter a Queue Name and click Browse");
163  
164         try {
165             connect();
166         } catch (JMSException ex) {
167             System.err.println("Could not initialize JMS: " + ex);
168             System.err.println(
169                 "Are you sure there is an imqbrokerd running on " +
170                 serverHost + ":" + serverPort + "?" );
171             usage();
172         }
173  
174     }
175  
176     private void shutdownJMS() {
177         try {
178             connection.close();
179         } catch (JMSException e) {
180             System.out.println("Exception closing JMS connection: " + e);
181         }
182     }
183  
184     /**
185      * Initialize JMS by creating Connection and Session.
186      */
187     private void initJMS() throws JMSException {
188         ConnectionFactory  cf = null;
189  
190         cf = new com.sun.messaging.ConnectionFactory();
191  
192         ((com.sun.messaging.ConnectionFactory)cf).setProperty(
193             com.sun.messaging.ConnectionConfiguration.imqBrokerHostName,
194             serverHost);
195         ((com.sun.messaging.ConnectionFactory)cf).setProperty(
196             com.sun.messaging.ConnectionConfiguration.imqBrokerHostPort,
197             String.valueOf(serverPort));
198  
199         connection = cf.createConnection();
200         session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
201     }
202  
203     /**
204      * Setup a consumer that listens on the Message Queue monitoring topic
205      * that sends out lists of destinations.
206      */
207     private void initDestListConsumer() throws JMSException {
208         metricTopic = session.createTopic(DEST_LIST_TOPIC_NAME);
209         metricSubscriber = session.createConsumer(metricTopic);
210         metricSubscriber.setMessageListener(this);
211     }
212  
213  
214  
215     /**
216      * Set text on footer
217      */
218     private void setFooter(String s) {
219         footerLabel.setText(s);
220         footerLabel.paintImmediately(footerLabel.getBounds());
221     }
222  
223     /**
224      * Show the contents of a message in a seperate popup window
225      */
226     private void showDetails(Message msg, int msgno) {
227         if (detailsFrame == null) {
228             // Create popup
229             detailsFrame = new JFrame();
230             detailsFrame.setTitle(QBrowser.title + " - Message Details");
231             detailsFrame.setBackground(Color.white);
232             detailsFrame.getContentPane().setLayout(new BorderLayout());
233  
234             headerPanel = new PropertyPanel();
235             headerPanel.setTitle("JMS Headers");
236             detailsFrame.getContentPane().add(BorderLayout.NORTH, headerPanel);
237  
238             propertyPanel = new PropertyPanel();
239             propertyPanel.setTitle("Message Properties");
240             detailsFrame.getContentPane().add(BorderLayout.CENTER, propertyPanel);
241  
242             bodyPanel = new PropertyPanel();
243             bodyPanel.setTitle("Message body");
244             detailsFrame.getContentPane().add(BorderLayout.SOUTH, bodyPanel);
245             detailsFrame.pack();
246         }
247  
248         // Load JMS headers from message
249         try {
250             HashMap hdrs = jmsHeadersToHashMap(msg);
251             headerPanel.setTitle("JMS Headers: Message #" + msgno);
252             headerPanel.load(hdrs);
253         } catch (JMSException ex) {
254             setFooter("Error: " + ex.getMessage());
255         }
256  
257         // Load message properties
258         HashMap props = new HashMap();
259         // Get all message properties and stuff into a hash table
260         try {
261             for (Enumeration enu = msg.getPropertyNames();
262                 enu.hasMoreElements();) {
263  
264                 String name = (enu.nextElement()).toString();
265                 props.put(name, (msg.getObjectProperty(name)).toString());
266             }
267         } catch (JMSException ex) {
268             setFooter("Error: " + ex.getMessage());
269         }
270         propertyPanel.load(props);
271  
272         // Load message body
273         bodyPanel.setTitle("Message Body: (" + QBrowser.messageType(msg) + ")");
274         bodyPanel.load(jmsMsgBodyAsString(msg));
275  
276         detailsFrame.show();
277     }
278  
279     private void connect() throws JMSException {
280         if (connection == null) {
281             setFooter("Connecting to " + serverHost + ":" +
282                        serverPort + "...");
283             initJMS();
284  
285             try {
286                 initDestListConsumer();
287             } catch (JMSException e) {
288                 // If we can't subscribe to the mq.metrics topic then we
289                 // are probably not running against an EE broker. That's
290                 // OK. It just means we can't populate the Destination
291                 // combo-box on the GUI.
292                 //System.out.println("Could not subscribe to " +
293                 //    DEST_LIST_TOPIC_NAME);
294             }
295             connection.start();
296             setFooter("Connected to " + serverHost + ":" + serverPort);
297         }
298     }
299  
300  
301     /**
302      * Browse the queue
303      */
304     private void doBrowse() {
305  
306         ComboBoxEditor editor = qBox.getEditor();
307         String name = (String)editor.getItem();
308         setFooter("Browsing " + name + "...");
309  
310         // Browse queue
311         try {
312             String selector = null;
313             Queue q = session.createQueue(name);
314             QueueBrowser qb;
315             if (selector == null) {
316                 qb = session.createBrowser(q);
317             } else {
318                 qb = session.createBrowser(q, selector);
319             }
320             // Load messages into table
321             MsgTable mt = (MsgTable)msgTable.getModel();
322             int n = mt.load(qb.getEnumeration());
323             setFooter(name + ": " + String.valueOf(n));
324             qb.close();
325         } catch (JMSException ex) {
326             setFooter(ex.getMessage());
327         }
328     }
329  
330     /**
331      * Add a name to the "Queue Name" combo box menu
332      */
333     private void addDestToMenu(String name) {
334         DefaultComboBoxModel  model  = (DefaultComboBoxModel)qBox.getModel();
335  
336         if (model.getIndexOf(name) < 0) {
337             // Name is not in menu. Add it.
338             model.addElement(name);
339         }
340     }
341  
342     /**
343      * Main
344      */
345     public static void main (String args[]) {
346  
347         for (int n = 0; n < args.length; n++) {
348             if (args[n].equals("-b")) {
349                 n++;
350                 serverHost = args[n];
351             } else if (args[n].equals("-p")) {
352                 n++;
353                 try {
354                     serverPort = Integer.parseInt(args[n]);
355                 } catch (NumberFormatException e) {
356                     System.err.println("Bad port number: " + args[n]);
357                     System.exit(1);
358                 }
359             } else {
360                 usage();
361             }
362         }
363  
364        JFrame frame = new JFrame();
365        frame.setTitle(QBrowser.title + " - " + serverHost + ":" + serverPort);
366        frame.setBackground(Color.white);
367        frame.getContentPane().setLayout(new BorderLayout());
368        frame.getContentPane().add("Center", new QBrowser());
369        frame.pack();
370        frame.show();
371     }
372  
373     private static void usage() {
374         System.out.println(
375             "usage: QBrowser [-b <brokerhost>] [-p <brokerport>]" + "\n" +
376             "   <brokerhost>    Host to connect to. Default is " +
377                 DEFAULT_BROKER_HOST +
378             "\n" +
379             "   <brokerport>    Port to connect to. Default is " +
380                 DEFAULT_BROKER_PORT
381             );
382         System.exit(1);
383     }
384  
385     public static void dumpException(Exception e) {
386         Exception linked = null;
387         if (e instanceof JMSException) {
388             linked = ((JMSException)e).getLinkedException();
389         }
390  
391         if (linked == null) {
392             e.printStackTrace();
393         } else {
394             System.err.println(e.toString());
395             linked.printStackTrace();
396         }
397     }
398  
399     /**
400      * Return a string description of the type of JMS message
401      */
402     static String messageType(Message m) {
403  
404         if (m instanceof TextMessage) {
405             return "TextMessage";
406         } else if (m instanceof BytesMessage) {
407             return "BytesMessage";
408         } else if (m instanceof MapMessage) {
409             return "MapMessage";
410         } else if (m instanceof ObjectMessage) {
411             return "ObjectMessage";
412         } else if (m instanceof StreamMessage) {
413             return "StreamMessage";
414         } else if (m instanceof Message) {
415             return "Message";
416         } else {
417             // Unknown Message type
418             String type = m.getClass().getName();
419             StringTokenizer st = new StringTokenizer(type, ".");
420             String s = null;
421             while (st.hasMoreElements()) {
422                 s = st.nextToken();
423             }
424             return s;
425         }
426     }
427  
428     /**
429      * Return a string representation of the body of a JMS
430      * bytes message. This is basically a hex dump of the body.
431      * Note, this only looks at the first 1K of the message body.
432      */
433     private static String jmsBytesBodyAsString(Message m) {
434         byte[] body = new byte[1024];
435         int n = 0;
436  
437         if (m instanceof BytesMessage) {
438             try {
439                 ((BytesMessage)m).reset();
440                 n = ((BytesMessage)m).readBytes(body);
441             } catch (JMSException ex) {
442                 return (ex.toString());
443             }
444         } else if (m instanceof StreamMessage) {
445             try {
446                 ((StreamMessage)m).reset();
447                 n = ((StreamMessage)m).readBytes(body);
448             } catch (JMSException ex) {
449                 return (ex.toString());
450             }
451         }
452  
453         if (n <= 0) {
454             return "<empty body>";
455         } else {
456             return(toHexDump(body, n) +
457                    ((n >= body.length ) ? "\n. . ." : "") );
458         }
459     }
460  
461     /**
462      * Return a string representation of a JMS message body
463      */
464     private static String jmsMsgBodyAsString(Message m) {
465  
466         if (m instanceof TextMessage) {
467             try {
468                 return ((TextMessage) m).getText();
469             } catch (JMSException ex) {
470                 return ex.toString();
471             }
472         } else if (m instanceof BytesMessage) {
473             return jmsBytesBodyAsString(m);
474         } else if (m instanceof MapMessage) {
475             MapMessage msg = (MapMessage)m;
476             HashMap props = new HashMap();
477             // Get all MapMessage properties and stuff into a hash table
478             try {
479                 for (Enumeration enu = msg.getMapNames();
480                     enu.hasMoreElements();) {
481                     String name = (enu.nextElement()).toString();
482                     props.put(name, (msg.getObject(name)).toString());
483                 }
484                 return props.toString();
485             } catch (JMSException ex) {
486                 return (ex.toString());
487             }
488         } else if (m instanceof ObjectMessage) {
489             ObjectMessage msg = (ObjectMessage)m;
490             Object obj = null;
491             try {
492                 obj = msg.getObject();
493                 if (obj != null) {
494                     return obj.toString();
495                 } else {
496                     return "null";
497                 }
498             } catch (Exception ex) {
499                 return (ex.toString());
500             }
501         } else if (m instanceof StreamMessage) {
502             return jmsBytesBodyAsString(m);
503         } else if (m instanceof Message) {
504             return "Can't get body for message of type Message";
505         }
506         return "Unknown message type " + m;
507     }
508  
509     /**
510      * Takes the JMS header fields of a JMS message and puts them in
511      * a HashMap
512      */
513     private static HashMap jmsHeadersToHashMap(Message m) throws JMSException {
514         HashMap hdrs = new HashMap();
515         String s = null;
516  
517         s = m.getJMSCorrelationID();
518         hdrs.put("JMSCorrelationID", s);
519  
520         s = String.valueOf(m.getJMSDeliveryMode());
521         hdrs.put("JMSDeliverMode", s);
522  
523         Destination d = m.getJMSDestination();
524         if (d != null) {
525             if (d instanceof Queue) {
526                 s = ((Queue)d).getQueueName();
527             } else {
528                 s = ((Topic)d).getTopicName();
529             }
530         } else {
531             s = "";
532         }
533         hdrs.put("JMSDestination", s);
534  
535         s = String.valueOf(m.getJMSExpiration());
536         hdrs.put("JMSExpiration", s);
537  
538         s = m.getJMSMessageID();
539         hdrs.put("JMSMessageID", s);
540  
541         s = String.valueOf(m.getJMSPriority());
542         hdrs.put("JMSPriority", s);
543  
544         s = String.valueOf(m.getJMSRedelivered());
545         hdrs.put("JMSRedelivered", s);
546  
547         d = m.getJMSDestination();
548         if (d != null) {
549             if (d instanceof Queue) {
550                 s = ((Queue)d).getQueueName();
551             } else {
552                 s = ((Topic)d).getTopicName();
553             }
554         } else {
555             s = "";
556         }
557         hdrs.put("JMSReplyTo", s);
558  
559         s = String.valueOf(m.getJMSTimestamp());
560         hdrs.put("JMSTimestamp", s);
561  
562         s = m.getJMSType();
563         hdrs.put("JMSType", s);
564  
565         return hdrs;
566     }
567  
568     /**
569      * Takes a buffer of bytes and returns a hex dump. Each hex digit
570      * represents 4 bits. The hex digits are formatted into groups of
571      * 4 (2 bytes, 16 bits). Each line has 8 groups, so each line represents
572      * 128 bits.
573      */
574     private static String toHexDump(byte[] buf, int length) {
575  
576         // Buffer must be an even length
577         if (buf.length % 2 != 0) {
578             throw new IllegalArgumentException();
579         }
580  
581         int value;
582         StringBuffer sb = new StringBuffer(buf.length * 2);
583  
584         /* Assume buf is in network byte order (most significant byte
585          * is buf[0]). Convert two byte pairs to a short, then
586          * display as a hex string.
587          */
588         int n = 0;
589         while (n < buf.length && n < length) {
590             value = buf[n + 1] & 0xFF;          // Lower byte
591             value |= (buf[n] << 8) & 0xFF00;    // Upper byte
592             String s = Integer.toHexString(value);
593             // Left bad with 0's
594             sb.append(pad[4 - s.length()]);
595             sb.append(s);
596             n += 2;
597  
598             if (n % 16 == 0) {
599                 sb.append("\n");
600             }  else {
601                 sb.append(" ");
602             }
603          }
604          return sb.toString();
605     }
606  
607     /**
608      * Consumer that listens on the MQ monitoring topic that sends
609      * out lists of destination names. We use this to update the
610      * combo-box menu.
611      */
612     public void onMessage(Message msg) {
613  
614         try  {
615             MapMessage mapMsg = (MapMessage)msg;
616             String type = mapMsg.getStringProperty("type");
617  
618             if (type.equals(DEST_LIST_TOPIC_NAME))  {
619                 String oneRow[] = new String[ 3 ];
620  
621                 TreeSet names = new TreeSet();
622  
623                 /*
624                  * Extract list of destinations
625                  */
626                 for (Enumeration e = mapMsg.getMapNames();
627                      e.hasMoreElements();) {
628                     String name = (String)e.nextElement();
629                     Hashtable values = (Hashtable)mapMsg.getObject(name);
630  
631                     // Sort names by putting them into TreeSet
632                     if (values.get("type").toString().equals("queue")) {
633                         names.add((String)values.get("name"));
634                     }
635                 }
636  
637                 // Add sorted names to combo box menu
638                 for (Iterator iter = names.iterator(); iter.hasNext();) {
639                     addDestToMenu((String)iter.next());
640                 }
641             } else {
642                 System.err.println(
643                     "Msg received: not destination list metric type");
644             }
645         } catch (Exception e)  {
646             System.err.println("onMessage: Exception caught: " + e);
647         }
648     }
649  
650     class OptionListener implements ItemListener {
651         public void itemStateChanged(ItemEvent e) {
652             System.out.println("ItemEvent");
653         }
654     }
655  
656     class ExitListener implements ActionListener {
657         public void actionPerformed(ActionEvent e) {
658             shutdownJMS();
659             System.exit(0);
660         }
661     }
662  
663     class BrowseListener implements ActionListener {
664         public void actionPerformed(ActionEvent e) {
665             doBrowse();
666         }
667     }
668  
669     class TableMouseListener extends MouseAdapter {
670         public void mouseClicked(MouseEvent e) {
671             if (e.getClickCount() == 2) {
672                 int row = msgTable.getSelectedRow();
673                 MsgTable mt = (MsgTable)msgTable.getModel();
674                 Message msg = mt.getMessageAtRow(row);
675                 showDetails(msg, row);
676             }
677         }
678     }
679  
680     class DetailsListener implements ActionListener {
681         public void actionPerformed(ActionEvent e) {
682             int row = msgTable.getSelectedRow();
683             if (row < 0) {
684                 setFooter("Please select a message");
685                 return;
686             }
687             MsgTable mt = (MsgTable)msgTable.getModel();
688             Message msg = mt.getMessageAtRow(row);
689             showDetails(msg, row);
690         }
691     }
692  
693  
694 /**
695  * A table of JMS Messages
696  */
697 class MsgTable extends AbstractTableModel {
698  
699     final String[] columnNames =
700                 {"#", "Timestamp", "Type", "Mode", "Priority"};
701  
702     SimpleDateFormat df =
703         new SimpleDateFormat("dd/MMM/yyyy:kk:mm:ss z");
704  
705     LinkedList list = null;
706  
707     public int getRowCount() {
708         if (list == null) {
709             return 0;
710         } else {
711             return list.size();
712         }
713     }
714  
715     public int getColumnCount() {
716         return columnNames.length;
717     }
718  
719     public String getColumnName(int column) {
720         return columnNames[column];
721     }
722  
723     public Object getValueAt(int row, int column) {
724         if (list == null) {
725             return null;
726         }
727  
728         Message m = (Message)list.get(row);
729  
730         if (m == null) {
731             return "null";
732         }
733  
734         try {
735             switch (column) {
736             case 0:
737                 // Message number is the same as the row number
738                 return new Integer(row);
739             case 1:
740                 // Need to format into date/time
741                 return df.format(new Date(m.getJMSTimestamp()));
742             case 2:
743                 return QBrowser.messageType(m);
744             case 3:
745                 // Delivery mode
746                 int mode = m.getJMSDeliveryMode();
747                 if (mode == DeliveryMode.PERSISTENT) {
748                     return "P";
749                 } else if (mode == DeliveryMode.NON_PERSISTENT) {
750                     return "NP";
751                 } else {
752                     return String.valueOf(mode) + "?";
753                 }
754             case 4:
755                 // Priority
756                 return new Integer(m.getJMSPriority());
757             default:
758                 return "Bad column value: " + column;
759             }
760         } catch (JMSException e) {
761             return ("Error: " + e);
762         }
763     }
764  
765  
766  
767     /**
768      * Load and enumeration of messages into the table
769      */
770     int load (Enumeration e) {
771         if (e == null) {
772             return 0;
773         }
774  
775         list = new LinkedList();
776  
777         while (e.hasMoreElements()) {
778             list.add(e.nextElement());
779         }
780  
781         fireTableDataChanged();
782  
783         return list.size();
784     }
785  
786     Message getMessageAtRow(int row) {
787         if (list == null) return null;
788         return((Message)list.get(row));
789     }
790 }
791  
792  
793 /**
794  * A panel with a text area that knows how to format and display
795  * a HashMap of values.
796  */
797 class PropertyPanel extends JPanel {
798  
799     JLabel      label = null;
800     JTextArea   textArea = null;
801     JScrollPane areaScrollPane = null;
802  
803     PropertyPanel() {
804         super(true);
805         setBorder(BorderFactory.createEtchedBorder());
806         setLayout(new BorderLayout());
807  
808         label = new JLabel();
809  
810         textArea = new JTextArea();
811         textArea.setFont(new Font("Monospaced", Font.PLAIN, 12));
812         textArea.setLineWrap(true);
813         textArea.setWrapStyleWord(true);
814  
815         areaScrollPane = new JScrollPane(textArea);
816         areaScrollPane.setVerticalScrollBarPolicy(
817             JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
818         areaScrollPane.setPreferredSize(new Dimension(500, 150));
819  
820         add(BorderLayout.NORTH, label);
821         add(BorderLayout.CENTER, areaScrollPane);
822     }
823  
824     void setTitle(String title) {
825         label.setText(title);
826     }
827  
828     /**
829      * Display a HashMap in the text window
830      */
831     void load(HashMap map) {
832  
833         StringBuffer buf = new StringBuffer();
834  
835         Set entries = map.entrySet();
836         Map.Entry entry = null;
837         Iterator iter = entries.iterator();
838         while (iter.hasNext()) {
839             entry = (Map.Entry)iter.next();
840             String key = entry.getKey().toString();
841  
842             Object o = entry.getValue();
843             String value = "";
844             if (o != null) {
845                 value = o.toString();
846             }
847  
848             buf.append(pad(key + ": ", 20));
849             buf.append(value + "\n");
850         }
851  
852         textArea.setText(buf.toString());
853  
854         areaScrollPane.scrollRectToVisible(new Rectangle(0, 0, 1, 1));
855  
856     }
857  
858     /**
859      * Display text in the text window
860      */
861     void load(String s) {
862         textArea.setText(s);
863     }
864  
865     /**
866      * Pad a string to the specified width, right justified.
867      * If the string is longer than the width you get back the
868      * original string.
869      */
870     String pad(String s, int width) {
871  
872         // Very inefficient, but we don't care
873         StringBuffer sb = new StringBuffer();
874         int padding = width - s.length();
875  
876         if (padding <= 0) {
877             return s;
878         }
879  
880         while (padding > 0) {
881             sb.append(" ");
882             padding--;
883         }
884         sb.append(s);
885         return sb.toString();
886     }
887 }
888 }