/*
* $Id$
*
* Copyright (c) 2000-2009 by Rodney Kinney, Brent Easton
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License (LGPL) as published by the Free Software Foundation.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, copies are available
* at http://www.opensource.org.
*/
package VASSAL.chat;
import java.awt.Component;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Properties;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import net.miginfocom.swing.MigLayout;
import org.jivesoftware.smack.util.StringUtils;
import VASSAL.chat.jabber.JabberClientFactory;
import VASSAL.chat.node.NodeClientFactory;
import VASSAL.chat.peer2peer.P2PClientFactory;
import VASSAL.configure.Configurer;
import VASSAL.i18n.Resources;
import VASSAL.tools.menu.MacOSXMenuManager;
/**
* Specifies the server implementation in the Preferences
*
* @author rkinney
*
*/
public class ServerConfigurer extends Configurer {
private static final String CONNECTED = Resources.getString("Server.please_disconnect"); //$NON-NLS-1$
private static final String DISCONNECTED = Resources.getString("Server.select_server_type"); //$NON-NLS-1$
private static final String JABBER_BUTTON = Resources.getString("Server.jabber"); //$NON-NLS-1$
private static final String P2P_BUTTON = Resources.getString("Server.direct"); //$NON-NLS-1$
private static final String LEGACY_BUTTON = Resources.getString("Server.legacy"); //$NON-NLS-1$
private static final String ENCODING = "UTF-8"; //$NON-NLS-1$
protected JComponent controls;
private JTextField jabberHost;
private HybridClient client;
private JRadioButton legacyButton;
private JRadioButton jabberButton;
private JTextField jabberAccountName;
private JPasswordField jabberPassword;
private JRadioButton p2pButton;
private JLabel header;
private JCheckBox jabberHostPrompt;
private JLabel jabberAccountPrompt;
private JLabel jabberPasswordPrompt;
private DocumentListener docListener;
public ServerConfigurer(String key, String name, HybridClient client) {
super(key, name, new Properties());
this.client = client;
client.addPropertyChangeListener(ChatServerConnection.CONNECTED, new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
enableControls(Boolean.TRUE.equals(evt.getNewValue()));
}
});
getControls();
setValue(buildLegacyProperties());
}
public Component getControls() {
if (controls == null) {
controls = new JPanel(new MigLayout());
header = new JLabel(DISCONNECTED);
controls.add(header, "wrap"); //$NON-NLS-1$
ButtonGroup group = new ButtonGroup();
jabberButton = new JRadioButton(JABBER_BUTTON);
jabberButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
noUpdate = true;
setValue(buildJabberProperties());
noUpdate = false;
}
jabberHostPrompt.setEnabled(jabberButton.isSelected());
jabberHost.setEnabled(jabberButton.isSelected() && jabberHostPrompt.isSelected());
jabberAccountName.setEnabled(jabberButton.isSelected());
jabberPassword.setEnabled(jabberButton.isSelected());
jabberAccountPrompt.setEnabled(jabberButton.isSelected());
jabberPasswordPrompt.setEnabled(jabberButton.isSelected());
}
});
jabberAccountPrompt = new JLabel(Resources.getString("Server.account_name")); //$NON-NLS-1$
jabberAccountPrompt.setEnabled(false);
jabberAccountName = new JTextField();
jabberAccountName.setEnabled(false);
jabberPasswordPrompt = new JLabel(Resources.getString("Server.password")); //$NON-NLS-1$
jabberPasswordPrompt.setEnabled(false);
jabberPassword = new JPasswordField();
jabberPassword.setEnabled(false);
jabberHostPrompt = new JCheckBox(Resources.getString("Server.host")); //$NON-NLS-1$
jabberHostPrompt.setEnabled(false);
jabberHost = new JTextField(18);
jabberHost.setEnabled(false);
jabberHostPrompt.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
jabberHost.setEnabled(jabberHostPrompt.isSelected() && jabberButton.isSelected());
docListener.changedUpdate(null);
}
});
jabberHost.setText(JabberClientFactory.DEFAULT_JABBER_HOST + ":" + JabberClientFactory.DEFAULT_JABBER_PORT); //$NON-NLS-1$
docListener = new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
updateValue();
}
private void updateValue() {
noUpdate = true;
setValue(buildJabberProperties());
noUpdate = false;
}
public void insertUpdate(DocumentEvent e) {
updateValue();
}
public void removeUpdate(DocumentEvent e) {
updateValue();
}
};
((AbstractDocument) jabberAccountName.getDocument()).setDocumentFilter(new DocumentFilter() {
@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
if (text != null) {
super.replace(fb, offset, length, StringUtils.escapeNode(text).toLowerCase(), attrs);
}
}
@Override
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
if (string != null) {
super.insertString(fb, offset, StringUtils.escapeNode(string).toLowerCase(), attr);
}
}
});
jabberHost.getDocument().addDocumentListener(docListener);
jabberAccountName.getDocument().addDocumentListener(docListener);
jabberPassword.getDocument().addDocumentListener(docListener);
// Disable Jabber server until next release
if ("true".equals(System.getProperty("enableJabber"))) { //$NON-NLS-1$ //$NON-NLS-2$
group.add(jabberButton);
controls.add(jabberButton, "wrap"); //$NON-NLS-1$
controls.add(jabberAccountPrompt, "gap 40"); //$NON-NLS-1$
controls.add(jabberAccountName, "wrap, growx"); //$NON-NLS-1$
controls.add(jabberPasswordPrompt, "gap 40"); //$NON-NLS-1$
controls.add(jabberPassword, "wrap, growx"); //$NON-NLS-1$
controls.add(jabberHostPrompt, "gap 40"); //$NON-NLS-1$
controls.add(jabberHost, "wrap, growx"); //$NON-NLS-1$
}
p2pButton = new JRadioButton(P2P_BUTTON);
p2pButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
noUpdate = true;
setValue(buildPeerProperties());
noUpdate = false;
}
}
});
group.add(p2pButton);
controls.add(p2pButton, "wrap"); //$NON-NLS-1$
legacyButton = new JRadioButton(LEGACY_BUTTON);
legacyButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
noUpdate = true;
setValue(buildLegacyProperties());
noUpdate = false;
}
}
});
controls.add(legacyButton);
group.add(legacyButton);
}
return controls;
}
private void enableControls(boolean connected) {
p2pButton.setEnabled(!connected);
legacyButton.setEnabled(!connected);
jabberButton.setEnabled(!connected);
jabberHostPrompt.setEnabled(!connected);
jabberHost.setEnabled(!connected && jabberHostPrompt.isSelected() && jabberButton.isSelected());
jabberAccountName.setEnabled(!connected && jabberButton.isSelected());
jabberPassword.setEnabled(!connected && jabberButton.isSelected());
header.setText(connected ? CONNECTED : DISCONNECTED);
}
protected Properties buildJabberProperties() {
Properties p = new Properties();
if (jabberHostPrompt.isSelected()) {
p.setProperty(ChatServerFactory.TYPE_KEY, JabberClientFactory.JABBER_SERVER_TYPE);
}
else {
// Build a Jabber server with dynamically-determined host and server
p.setProperty(ChatServerFactory.TYPE_KEY, DynamicClientFactory.DYNAMIC_TYPE);
p.setProperty(DynamicClientFactory.DYNAMIC_TYPE, JabberClientFactory.JABBER_SERVER_TYPE);
}
p.putAll(getJabberConfigProperties());
return p;
}
protected Properties getJabberConfigProperties() {
Properties p = new Properties();
p.setProperty(JabberClientFactory.JABBER_LOGIN, jabberAccountName.getText());
p.setProperty(JabberClientFactory.JABBER_PWD, new String(jabberPassword.getPassword()));
String host = jabberHost.getText();
String port = "5222"; //$NON-NLS-1$
int idx = host.indexOf(':'); //$NON-NLS-1$
if (idx > 0) {
port = host.substring(idx + 1);
host = host.substring(0, idx);
}
p.setProperty(JabberClientFactory.JABBER_HOST, host);
p.setProperty(JabberClientFactory.JABBER_PORT, port);
return p;
}
protected Properties buildPeerProperties() {
Properties p = new Properties();
p.setProperty(ChatServerFactory.TYPE_KEY, P2PClientFactory.P2P_TYPE);
p.putAll(getJabberConfigProperties());
return p;
}
protected Properties buildLegacyProperties() {
Properties p = new Properties();
// Build a legacy server with dynamically-determined host and server
p.setProperty(ChatServerFactory.TYPE_KEY, DynamicClientFactory.DYNAMIC_TYPE);
p.setProperty(DynamicClientFactory.DYNAMIC_TYPE, NodeClientFactory.NODE_TYPE);
p.putAll(getJabberConfigProperties());
return p;
}
public String getValueString() {
String s = ""; //$NON-NLS-1$
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
Properties p = (Properties) getValue();
if (p != null) {
p.store(out, null);
}
s = new String(out.toByteArray(), ENCODING);
}
// FIXME: review error message
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// FIXME: review error message
catch (IOException e) {
e.printStackTrace();
}
return s;
}
public void setValue(Object o) {
super.setValue(o);
if (!noUpdate && o instanceof Properties && controls != null) {
Properties p = (Properties) o;
String type = p.getProperty(ChatServerFactory.TYPE_KEY, JabberClientFactory.JABBER_SERVER_TYPE);
String finalType = type;
if (DynamicClientFactory.DYNAMIC_TYPE.equals(type)) {
finalType = p.getProperty(DynamicClientFactory.DYNAMIC_TYPE);
}
if (NodeClientFactory.NODE_TYPE.equals(finalType)) {
legacyButton.setSelected(true);
}
else if (JabberClientFactory.JABBER_SERVER_TYPE.equals(finalType)) {
jabberButton.setSelected(true);
jabberHostPrompt.setSelected(type.equals(finalType));
}
else if (P2PClientFactory.P2P_TYPE.equals(finalType)) {
p2pButton.setSelected(true);
}
jabberAccountName.setText(p.getProperty(JabberClientFactory.JABBER_LOGIN));
jabberPassword.setText(p.getProperty(JabberClientFactory.JABBER_PWD));
jabberHost.setText(p.getProperty(JabberClientFactory.JABBER_HOST, JabberClientFactory.DEFAULT_JABBER_HOST) + ":" //$NON-NLS-1$
+ p.getProperty(JabberClientFactory.JABBER_PORT, JabberClientFactory.DEFAULT_JABBER_PORT));
}
if (client != null && !CONNECTED.equals(header.getText())) {
client.setDelegate(ChatServerFactory.build(getServerInfo()));
}
}
public void setValue(String s) {
Properties p = new Properties();
try {
p.load(new ByteArrayInputStream(s.getBytes(ENCODING)));
}
// FIXME: review error message
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// FIXME: review error message
catch (IOException e) {
e.printStackTrace();
}
setValue(p);
}
private Properties getServerInfo() {
Properties p = (Properties) getValue();
if (p == null) {
p = new Properties();
}
else {
p = new Properties(p);
}
if (DynamicClientFactory.DYNAMIC_TYPE.equals(p.getProperty(ChatServerFactory.TYPE_KEY))) {
p.remove(JabberClientFactory.JABBER_HOST);
p.remove(JabberClientFactory.JABBER_PORT);
}
return p;
}
public static void main(String[] args) {
ChatServerFactory.register(NodeClientFactory.NODE_TYPE, new NodeClientFactory());
ChatServerFactory.register(DynamicClientFactory.DYNAMIC_TYPE, new DynamicClientFactory());
ChatServerFactory.register(P2PClientFactory.P2P_TYPE, new P2PClientFactory());
ChatServerFactory.register(JabberClientFactory.JABBER_SERVER_TYPE, new JabberClientFactory());
new MacOSXMenuManager();
HybridClient c = new HybridClient();
ServerConfigurer config = new ServerConfigurer("server", "server", c); //$NON-NLS-1$ //$NON-NLS-2$
JFrame f = new JFrame();
f.getContentPane().add(config.getControls());
f.pack();
f.setVisible(true);
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}