edu.clemson.cs.nestbed.client.gui.MoteConfigPanel.java Source code

Java tutorial

Introduction

Here is the source code for edu.clemson.cs.nestbed.client.gui.MoteConfigPanel.java

Source

/* $Id$ */
/*
 * MoteConfigPanel.java
 *
 * Network Embedded Sensor Testbed (NESTbed)
 *
 * Copyright (C) 2006-2007
 * Dependable Systems Research Group
 * School of Computing
 * Clemson University
 * Andrew R. Dalton and Jason O. Hallstrom
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the
 *
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301, USA.
 */
package edu.clemson.cs.nestbed.client.gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.JSpinner;
import javax.swing.JToolTip;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import edu.clemson.cs.nestbed.common.management.configuration.MoteDeploymentConfigurationManager;
import edu.clemson.cs.nestbed.common.management.configuration.MoteManager;
import edu.clemson.cs.nestbed.common.management.configuration.MoteTypeManager;
import edu.clemson.cs.nestbed.common.management.configuration.ProgramManager;
import edu.clemson.cs.nestbed.common.model.Mote;
import edu.clemson.cs.nestbed.common.model.MoteDeploymentConfiguration;
import edu.clemson.cs.nestbed.common.model.MoteTestbedAssignment;
import edu.clemson.cs.nestbed.common.model.MoteType;
import edu.clemson.cs.nestbed.common.model.Program;
import edu.clemson.cs.nestbed.common.util.RemoteObserver;

public class MoteConfigPanel extends MotePanel {
    private final static Log log = LogFactory.getLog(MoteConfigPanel.class);

    private final static Color BG_COLOR = Color.WHITE;
    private final static int MIN_RADIO_POWER = 1;
    private final static int MAX_RADIO_POWER = 31;
    private final static int RADIO_POWER_INCR = 1;
    private final static int LABEL_WIDTH = 20;
    private final static int LABEL_HEIGHT = 20;
    private final static int SPINNER_WIDTH = 40;
    private final static int SPINNER_HEIGHT = 20;

    private ProgramManager programManager;
    private MoteDeploymentConfigurationManager mdcManager;
    private MoteTestbedAssignment mtbAssignment;
    private Program program;
    private int projDepConfID;
    private Mote mote;
    private MoteType moteType;
    private MoteDeploymentConfiguration moteDepConfig;
    private Image icon;
    private JSpinner radioSpinner;
    private ChangeListener radioChangeListener;

    public MoteConfigPanel(MoteTestbedAssignment mtbAssignment, ProgramManager programManager, int projDepConfID,
            MoteManager moteManager, MoteTypeManager moteTypeManager, MoteDeploymentConfigurationManager mdcManager)
            throws RemoteException, NotBoundException, MalformedURLException {

        this.programManager = programManager;
        this.mtbAssignment = mtbAssignment;
        this.projDepConfID = projDepConfID;
        this.mote = moteManager.getMote(mtbAssignment.getMoteID());
        this.moteType = moteTypeManager.getMoteType(mote.getMoteTypeID());
        this.mdcManager = mdcManager;
        this.moteDepConfig = mdcManager.getMoteDeploymentConfiguration(projDepConfID, mote.getID());
        this.radioChangeListener = new RadioChangeListener();
        this.radioSpinner = new JSpinner(
                new SpinnerNumberModel(MAX_RADIO_POWER, MIN_RADIO_POWER, MAX_RADIO_POWER, RADIO_POWER_INCR));

        setIcon(new ImageIcon(moteType.getImage()).getImage());

        if (this.moteDepConfig != null) {
            this.program = programManager.getProgram(moteDepConfig.getProgramID());
            radioSpinner.setValue(moteDepConfig.getRadioPowerLevel());
        } else {
            radioSpinner.setEnabled(false);
        }
        radioSpinner.setToolTipText("Radio Power Level");

        Dimension labelSize = new Dimension(LABEL_WIDTH, LABEL_HEIGHT);
        JLabel addressLabel = new JLabel("" + mtbAssignment.getMoteAddress());
        addressLabel.setSize(labelSize);
        addressLabel.setPreferredSize(labelSize);

        Dimension spinnerSize = new Dimension(SPINNER_WIDTH, SPINNER_HEIGHT);
        radioSpinner.setSize(spinnerSize);
        radioSpinner.setPreferredSize(spinnerSize);
        radioSpinner.addChangeListener(radioChangeListener);

        setToolTipText(getToolTipString());
        addMouseListener(new MotePanelMouseListener());

        add(addressLabel);
        addressLabel.setLocation(2, 0);

        add(radioSpinner);
        radioSpinner.setLocation(getWidth() - SPINNER_WIDTH - 2, getHeight() - SPINNER_HEIGHT - 2);

        mdcManager.addRemoteObserver(new MoteDeploymentConfigObserver());
        new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, new ProgramDropTarget(), true);
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        if (moteDepConfig == null) {
            paintDisabledPattern(g);
        }
    }

    public String getMoteTosPlatform() {
        return moteType.getTosPlatform();
    }

    private String getToolTipString() {
        StringBuffer tip = new StringBuffer("<html><table border=0 cellspacing=0 cellpadding=1>" + "<tr>"
                + "    <th align=left>" + "Address:  " + "</th>" + "    <td>" + mtbAssignment.getMoteAddress()
                + "</td>" + "</tr><tr>" + "    <th align=left>" + "Serial Number:  " + "</th>" + "    <td>"
                + mote.getMoteSerialID() + "</td>" + "</tr><tr>" + "    <th align=left>" + "Type:  " + "</th>"
                + "    <td>" + moteType.getName() + "</td>" + "</tr><tr>" + "    <th align=left>" + "Total ROM:  "
                + "</th>" + "    <td>" + moteType.getTotalROM() + "</td>" + "</tr><tr>" + "    <th align=left>"
                + "Total RAM:  " + "</th>" + "    <td>" + moteType.getTotalRAM() + "</td>" + "</tr><tr>"
                + "    <th align=left>" + "Total EEPROM:  " + "</th>" + "    <td>" + moteType.getTotalEEPROM()
                + "</td>" + "</tr><tr>");

        if (moteDepConfig != null) {
            tip.append("<th align=left>" + "Program Name: " + "</th>" + "<td>" + program.getName() + "</td>"
                    + "</tr><tr>" + "<th align=left>" + "Radio Power Level: " + "</th>" + "<td>"
                    + moteDepConfig.getRadioPowerLevel() + "</td>");
        } else {
            tip.append("<th align=left colspan=2>Unconfigured</th>");
        }

        tip.append("</tr></table></html>");

        return tip.toString();
    }

    protected class ProgramDropTarget extends DropTargetAdapter {
        private final String MIME_TYPE = DataFlavor.javaJVMLocalObjectMimeType + ";class=edu.clemson.cs.nestbed."
                + "common.model.Program";
        private DataFlavor programFlavor;

        public ProgramDropTarget() {
            try {
                this.programFlavor = new DataFlavor(MIME_TYPE);
            } catch (ClassNotFoundException ex) {
                log.error("ClassNotFoundException:\n", ex);
                ClientUtils.displayErrorMessage(MoteConfigPanel.this, ex);
            }
        }

        public void drop(DropTargetDropEvent e) {
            try {
                Transferable t = e.getTransferable();
                Program program = (Program) t.getTransferData(programFlavor);

                mdcManager.setMoteDeploymentConfiguration(projDepConfID, mote.getID(), program.getID(),
                        MAX_RADIO_POWER);
            } catch (UnsupportedFlavorException ex) {
                log.error("DataFlavor " + programFlavor + " unsupported", ex);
                ClientUtils.displayErrorMessage(MoteConfigPanel.this, ex);
            } catch (IOException ex) {
                log.error("I/O exception on data flavor " + programFlavor, ex);
                ClientUtils.displayErrorMessage(MoteConfigPanel.this, ex);
            }
        }
    }

    protected class RadioChangeListener implements ChangeListener {
        public void stateChanged(ChangeEvent e) {
            try {
                int pow = Integer.parseInt(radioSpinner.getValue().toString());
                mdcManager.setMoteDeploymentConfiguration(projDepConfID, mote.getID(), program.getID(), pow);
            } catch (RemoteException ex) {
                log.error("Remote exception while setting config", ex);
                ClientUtils.displayErrorMessage(MoteConfigPanel.this, ex);
            }
        }
    }

    protected class MoteDeploymentConfigObserver extends UnicastRemoteObject implements RemoteObserver {
        public MoteDeploymentConfigObserver() throws RemoteException {
            super();
        }

        public void update(Serializable msg, Serializable arg) throws RemoteException {
            MoteDeploymentConfigurationManager.Message message;
            MoteDeploymentConfiguration mdConfig;

            message = (MoteDeploymentConfigurationManager.Message) msg;
            mdConfig = (MoteDeploymentConfiguration) arg;

            switch (message) {
            case NEW_CONFIG:
                if ((mdConfig.getMoteID() == mote.getID())
                        && ((moteDepConfig == null) || (mdConfig.getID() == moteDepConfig.getID())
                                || (mdConfig.getProjectDeploymentConfigurationID() == projDepConfID))) {
                    log.debug("Adding new/updating mote deployment " + "configuration");

                    moteDepConfig = mdConfig;
                    //
                    // This is a nasty hack.  We update the value of
                    // the spinner when we get an update; however, updating
                    // the spinner generates a new update event.  Here,
                    // we deregister the listener, update the component,
                    // then re-add the listener.
                    //
                    // We could have fixed this using some state variable
                    // to indicate we generated the update.  That might
                    // be a better solution than this.
                    //
                    synchronized (radioSpinner) {
                        radioSpinner.removeChangeListener(radioChangeListener);
                        radioSpinner.setEnabled(true);
                        radioSpinner.setValue(moteDepConfig.getRadioPowerLevel());
                        radioSpinner.addChangeListener(radioChangeListener);
                    }
                    program = programManager.getProgram(moteDepConfig.getProgramID());
                    setToolTipText(getToolTipString());
                    MoteConfigPanel.this.repaint();
                }
                break;

            case DELETE_CONFIG:
                log.debug("Mote deployment configuration removal");

                if (moteDepConfig != null) {
                    log.debug("moteDepConfig is not null\n" + "id:          " + moteDepConfig.getID() + "\n"
                            + "mdConfig id: " + mdConfig.getID());

                    if (moteDepConfig.getID() == mdConfig.getID()) {
                        moteDepConfig = null;
                        // More hackery like above
                        synchronized (radioSpinner) {
                            radioSpinner.removeChangeListener(radioChangeListener);
                            radioSpinner.setEnabled(false);
                            radioSpinner.setValue(MAX_RADIO_POWER);
                            radioSpinner.addChangeListener(radioChangeListener);
                        }
                        setToolTipText(getToolTipString());
                        MoteConfigPanel.this.repaint();
                    }
                } else {
                    log.warn("moteDepConfig is null");
                }
                break;

            default:
                log.error("Unknown message:  " + msg);
                break;
            }
        }
    }

    protected class MotePanelMouseListener extends MouseAdapter {
        private JPopupMenu menu;
        private JMenuItem title;
        private JMenuItem unconfigureMote;

        public MotePanelMouseListener() {
            menu = new JPopupMenu();
            title = new JMenuItem("Mote " + mtbAssignment.getMoteAddress() + " (" + mote.getMoteSerialID() + ")");
            unconfigureMote = new JMenuItem("Unconfigure Mote Deployment");

            title.setEnabled(false);
            menu.add(title);
            menu.add(new JSeparator());

            unconfigureMote.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    try {
                        mdcManager.deleteMoteDeploymentConfiguration(moteDepConfig.getID());
                    } catch (RemoteException ex) {
                        log.error("Remote Exception", ex);
                        ClientUtils.displayErrorMessage(MoteConfigPanel.this, ex);
                    }
                }
            });

            menu.add(unconfigureMote);
        }

        public void mouseClicked(MouseEvent e) {
            if (SwingUtilities.isRightMouseButton(e) && moteDepConfig != null) {
                menu.show(MoteConfigPanel.this, e.getX(), e.getY());
            }
        }
    }
}