org.apache.cassandra.contrib.circuit.CircuitFrame.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.cassandra.contrib.circuit.CircuitFrame.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.cassandra.contrib.circuit;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Event;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import com.google.common.collect.Sets;
import org.apache.commons.lang.time.FastDateFormat;

public class CircuitFrame extends JFrame implements ActionListener {
    private static final long serialVersionUID = 1L;
    private static final String appTitle = "Circuit";
    private static final Dimension defaultSize = new Dimension(550, 600);
    private static final FastDateFormat DATE_FORMATTER = FastDateFormat.getInstance("HH:mm:ss");

    private static final Lock verifyLock = new ReentrantLock();

    private RingModel ringModel;
    private RingPanel ringPanel;
    private JTextArea statusOutput;

    private JMenuBar menuBar;
    private JMenuItem quitMI, verifyMI, aboutMI;

    public CircuitFrame(String hostname, int port) {
        super(appTitle);
        setSize(defaultSize);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // The menu bar w/ items.
        menuBar = new JMenuBar();
        setJMenuBar(menuBar);

        JMenu fileMenu = new JMenu("File");
        fileMenu.setMnemonic(KeyEvent.VK_F);
        menuBar.add(fileMenu);

        quitMI = new JMenuItem("Quit");
        quitMI.setMnemonic(KeyEvent.VK_Q);
        quitMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, Event.CTRL_MASK));
        quitMI.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        fileMenu.add(quitMI);

        JMenu toolsMenu = new JMenu("Tools");
        toolsMenu.setMnemonic(KeyEvent.VK_T);
        menuBar.add(toolsMenu);

        verifyMI = new JMenuItem("Verify Ring");
        verifyMI.addActionListener(this);
        toolsMenu.add(verifyMI);

        JMenu helpMenu = new JMenu("Help");
        helpMenu.setMnemonic(KeyEvent.VK_H);
        menuBar.add(helpMenu);

        aboutMI = new JMenuItem("About");
        aboutMI.setMnemonic(KeyEvent.VK_A);
        aboutMI.addActionListener(this);
        helpMenu.add(aboutMI);

        // FIXME: a progress dialog should be up while instantiating RingPanel
        ringModel = new RingModel(hostname, port);
        ringPanel = new RingPanel(ringModel);

        statusOutput = new JTextArea();
        statusOutput.setEditable(false);
        Component logPanel = new JScrollPane(statusOutput);

        JSplitPane contentPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, ringPanel, logPanel);
        setContentPane(contentPane);

        // Order matters here...
        ringPanel.setPreferredSize(getSize());
        setVisible(true);
        contentPane.setDividerLocation(0.8);
    }

    public void actionPerformed(ActionEvent e) {
        Object src = e.getSource();

        if (src == verifyMI) {
            verifyRing();
        } else if (src == aboutMI) {
            new AboutDialog(this).setVisible(true);
        }
    }

    /**
     * For each node, retrieve that nodes list and compare it to ours. If the
     * list of remote nodes doesn't match (it's long or short), then the node is
     * flagged accordingly and an error message is written to the status display.
     */
    private void verifyRing() {
        new Thread("VERIFY-RING") {
            public void run() {
                verifyLock.lock();
                ringPanel.setVerifying(true);
                try {
                    writeStatusOutput("Beginning ring verification...");
                    for (Node node : ringModel.getNodes()) {
                        // Skip the node we already queried at startup
                        if (node.isSeed())
                            continue;

                        writeStatusOutput("Verifying %s (ring) against reference node", node);
                        node.setSelected(true);

                        SwingUtilities.invokeLater(new Runnable() {
                            public void run() {
                                ringPanel.repaint();
                            }
                        });

                        // uncomment this to simulate a slow running verification process
                        //                        try {Thread.currentThread().sleep(2000L); } catch (Exception ex) { }

                        Set<Node> othersSet, nodesSet;
                        try {
                            othersSet = new HashSet<Node>(ringModel.getRemoteNodes(node.getHost()));
                        } catch (IOException e) {
                            e.printStackTrace();
                            writeStatusOutput("Error retrieving node list from %s", node.getHost());
                            continue;
                        }

                        nodesSet = new HashSet<Node>(ringModel.getNodes());

                        for (Node upShort : Sets.difference(nodesSet, othersSet)) {
                            node.setStatus(NodeStatus.SHORT);
                            writeStatusOutput("%s: missing node %s", node, upShort);
                        }

                        for (Node upLong : Sets.difference(othersSet, nodesSet)) {
                            node.setStatus(NodeStatus.LONG);
                            writeStatusOutput("%s: contains node %s missing from reference list", node, upLong);
                        }

                        node.setSelected(false);
                    }

                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            ringPanel.repaint();
                        }
                    });
                    writeStatusOutput("Ring verification complete.");
                } finally {
                    verifyLock.unlock();
                    ringPanel.setVerifying(false);
                }
            }
        }.start();
    }

    // TODO: use StatusLevel to distinguish message priorities.
    private void writeStatusOutput(String msg, StatusLevel level, Object... args) {
        String pref = String.format("[%s] ", DATE_FORMATTER.format(new Date()));
        statusOutput.append(String.format(pref + msg + "\n", args));
        statusOutput.setCaretPosition(statusOutput.getDocument().getLength());
    }

    private void writeStatusOutput(String msg, Object... args) {
        writeStatusOutput(msg, StatusLevel.INFO, args);
    }

    public static void main(final String[] args) throws IOException {
        if (args.length != 2) {
            System.err.println("Usage: java " + CircuitFrame.class.getName() + " <host> <port>");
            System.exit(1);
        }
        try {
            SwingUtilities.invokeAndWait(new Runnable() {
                public void run() {
                    CircuitFrame app = new CircuitFrame(args[0], Integer.parseInt(args[1]));
                    app.setVisible(true);
                }
            });
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

enum StatusLevel {
    INFO, WARN, ERROR, CRITICAL, DEBUG,
}