
eu.hgross.blaubot.ui.BlaubotServerPanel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of blaubot Show documentation
Show all versions of blaubot Show documentation
An easy to use publish/subscribe middleware to create and communicate through dynamically created adhoc networks.
package eu.hgross.blaubot.ui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import eu.hgross.blaubot.core.BlaubotDevice;
import eu.hgross.blaubot.core.BlaubotFactory;
import eu.hgross.blaubot.core.BlaubotKingdom;
import eu.hgross.blaubot.core.BlaubotServer;
import eu.hgross.blaubot.core.IBlaubotServerLifeCycleListener;
import eu.hgross.blaubot.core.acceptor.ConnectionMetaDataDTO;
import eu.hgross.blaubot.core.acceptor.IBlaubotConnectionAcceptor;
import eu.hgross.blaubot.util.Log;
/**
* Shows the server state and connected kingdoms.
*/
public class BlaubotServerPanel extends JPanel {
private static final String LOG_TAG = "StatusViewPanel";
private static final long UPDATE_INTERVAL = 350;
private BlaubotServer mBlaubotServer;
/**
* Starts/Stops the whole server (if registered)
*/
private final JButton mStartStopButton;
/**
* The container which holds the selected kingdom's view
*/
private final JPanel mBlaubotKingdomViewContainer;
/**
* The listview of kindomgs of the split pane
*/
private final JList mKingdomListView;
/**
* the model for the kindom list
*/
private final DefaultListModel mKingdomListViewModel;
/**
* Shows informations about the server (acceptor, ip, ...)
*/
private final JLabel mServerInfoLabel;
/**
* Holds connected BlaubotKingdoms and their views.
*/
private final ConcurrentHashMap mBlaubotKingdomViews;
/**
* Schedules the updateUiTask for the start/stop button state.
* Yeah it's hacky and should be refactored.
*/
private ScheduledExecutorService scheduledThreadPoolExecutor;
/**
* updates the start/stop state
* TODO add listeners for start/stop to the server instead of polling
*/
private Runnable updateUiTask = new Runnable() {
@Override
public void run() {
setButtonText();
}
};
public BlaubotServerPanel() {
super();
this.scheduledThreadPoolExecutor = Executors.newSingleThreadScheduledExecutor();
scheduledThreadPoolExecutor.scheduleAtFixedRate(updateUiTask, (long) 0, UPDATE_INTERVAL, TimeUnit.MILLISECONDS);
setLayout(new GridBagLayout());
this.mBlaubotKingdomViews = new ConcurrentHashMap<>();
this.mKingdomListViewModel = new DefaultListModel<>();
this.mKingdomListView = new JList<>(mKingdomListViewModel);
this.mKingdomListView.setMinimumSize(new Dimension(100, 200));
this.mKingdomListView.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
this.mKingdomListView.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
final String selectedKingdomUniqueDeviceId = mKingdomListView.getSelectedValue();
if (selectedKingdomUniqueDeviceId == null) {
return;
}
// find blaubot kingdom
BlaubotKingdom kingdom = null;
for (BlaubotKingdom k : mBlaubotKingdomViews.keySet()) {
if (k.getKingDevice().getUniqueDeviceID().equals(selectedKingdomUniqueDeviceId)) {
kingdom = k;
}
}
if (kingdom == null) {
return;
}
final BlaubotKingdomView blaubotKingdomView = mBlaubotKingdomViews.get(kingdom);
mBlaubotKingdomViewContainer.removeAll();
mBlaubotKingdomViewContainer.add(blaubotKingdomView);
updateUI();
}
});
this.mBlaubotKingdomViewContainer = new JPanel();
this.mStartStopButton = new JButton();
this.mStartStopButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (mBlaubotServer == null) {
if (Log.logWarningMessages()) {
Log.w(LOG_TAG, "Blaubot not set - ignoring onClick.");
}
return;
}
mStartStopButton.setEnabled(false);
if (mBlaubotServer.isStarted()) {
mBlaubotServer.stopBlaubotServer();
} else {
mBlaubotServer.startBlaubotServer();
}
}
});
this.mServerInfoLabel = new JLabel();
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(2, 2, 2, 2);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
c.gridheight = 1;
c.gridwidth = 2;
add(mStartStopButton, c);
c.gridy++;
add(mServerInfoLabel, c);
c.gridwidth = 1;
c.gridx = 0;
c.gridy++;
add(new JLabel("Connected kingdoms:"), c);
c.gridx = 1;
add(new JLabel("Details:"), c);
c.fill = GridBagConstraints.BOTH;
c.gridx = 0;
c.gridy++;
add(mKingdomListView, c);
c.gridx = 1;
add(mBlaubotKingdomViewContainer, c);
}
private IBlaubotServerLifeCycleListener mServerLifeCycleListener = new IBlaubotServerLifeCycleListener() {
@Override
public void onKingdomConnected(BlaubotKingdom kingdom) {
BlaubotKingdomView bkv = new BlaubotKingdomView();
bkv.registerBlaubotKingdomInstance(kingdom);
Component prev = mBlaubotKingdomViews.put(kingdom, bkv);
if (prev != null) {
removeView((BlaubotKingdomView) prev, kingdom);
}
mKingdomListViewModel.addElement(kingdom.getKingDevice().getUniqueDeviceID());
boolean nothingSelected = mKingdomListView.getSelectedIndex() == -1;
if (nothingSelected) {
mKingdomListView.setSelectedIndex(0);
}
updateUI();
}
@Override
public void onKingdomDisconnected(BlaubotKingdom kingdom) {
System.out.println("disc: " + kingdom);
Component remove = mBlaubotKingdomViews.remove(kingdom);
if (remove != null) {
removeView((BlaubotKingdomView) remove, kingdom);
}
updateUI();
}
private void removeView(BlaubotKingdomView view, BlaubotKingdom kingdom) {
view.unregisterBlaubotKingdomInstance();
mKingdomListViewModel.removeElement(kingdom.getKingDevice().getUniqueDeviceID());
// remove from container, if set
mBlaubotKingdomViewContainer.remove(view);
}
};
private void setButtonText() {
if (mBlaubotServer == null) {
return;
}
final boolean started = mBlaubotServer.isStarted();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// await either started or stopped
if (started) {
mStartStopButton.setText("Stop BlaubotServer");
} else {
mStartStopButton.setText("Start BlaubotServer");
}
mStartStopButton.setEnabled(true);
}
});
}
public void registerBlaubotServerInstance(BlaubotServer blaubotServer) {
if (this.mBlaubotServer != null) {
unregisterBlaubotServerInstance();
}
this.mBlaubotServer = blaubotServer;
blaubotServer.addServerLifeCycleListener(mServerLifeCycleListener);
setUpInfoLabel();
setButtonText();
}
public void unregisterBlaubotServerInstance() {
if (this.mBlaubotServer != null) {
mBlaubotServer.removeServerLifeCycleListener(mServerLifeCycleListener);
}
this.mBlaubotServer = null;
}
/**
* Updates the general server information textview.
*/
private void setUpInfoLabel() {
final String labelTemplate = "" +
"" +
" " +
" " +
" Acceptors: " +
" %s " +
" " +
" " +
" ConnectionMetaData: " +
" %s " +
" " +
"
" +
"";
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (mBlaubotServer == null) {
mServerInfoLabel.setText("No server instance registered to GUI.");
} else {
final List acceptors = mBlaubotServer.getAcceptors();
final ArrayList connectionMetaData = new ArrayList<>();
for (IBlaubotConnectionAcceptor acceptor : acceptors) {
connectionMetaData.add(acceptor.getConnectionMetaData());
}
mServerInfoLabel.setText(String.format(labelTemplate, acceptors, connectionMetaData));
}
}
});
}
/**
* Creates the gui for the server and displays the returned JFrame in a new Thread.
*
* @param blaubotServer the server instance
* @return the JFrame that is shown.
*/
public static JFrame createAndshowGui(final BlaubotServer blaubotServer) {
FutureTask futureTask = new FutureTask(new Callable() {
@Override
public JFrame call() throws Exception {
BlaubotServerPanel serverPanel = new BlaubotServerPanel();
serverPanel.registerBlaubotServerInstance(blaubotServer);
JFrame frame = new JFrame();
frame.getContentPane().setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setMinimumSize(new Dimension(900, 500));
frame.add(serverPanel);
frame.pack();
frame.setVisible(true);
frame.setTitle("Blaubot Server");
return frame;
}
});
new Thread(futureTask).start();
try {
return futureTask.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws ClassNotFoundException {
final BlaubotServer websocketServer = BlaubotFactory.createBlaubotWebsocketServer(new BlaubotDevice("Server1"));
BlaubotServerPanel.createAndshowGui(websocketServer);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy