package org.basex.gui.dialog;
import static org.basex.core.Text.*;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.io.IOException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.basex.BaseXServer;
import org.basex.core.Commands.CmdPerm;
import org.basex.core.BaseXException;
import org.basex.core.Context;
import org.basex.core.MainProp;
import org.basex.core.cmd.Exit;
import org.basex.core.cmd.ShowDatabases;
import org.basex.core.cmd.ShowSessions;
import org.basex.gui.GUI;
import org.basex.gui.GUIConstants;
import org.basex.gui.GUIConstants.Msg;
import org.basex.gui.GUIProp;
import org.basex.gui.layout.BaseXBack;
import org.basex.gui.layout.BaseXButton;
import org.basex.gui.layout.BaseXCombo;
import org.basex.gui.layout.BaseXEditor;
import org.basex.gui.layout.BaseXLabel;
import org.basex.gui.layout.BaseXLayout;
import org.basex.gui.layout.BaseXPassword;
import org.basex.gui.layout.BaseXTabs;
import org.basex.gui.layout.BaseXTextField;
import org.basex.gui.layout.TableLayout;
import org.basex.io.IOFile;
import org.basex.server.ClientSession;
import org.basex.util.Token;
import org.basex.util.Util;
import org.basex.util.list.StringList;
/**
* Dialog window for displaying information about the server.
*
* @author BaseX Team 2005-12, BSD License
* @author Andreas Weiler
*/
public final class DialogServer extends Dialog {
/** Password textfield. */
private final BaseXPassword logpass;
/** Tabulators. */
final BaseXTabs tabs;
/** User panel. */
final DialogUser user = new DialogUser(true, this);
/** Databases panel. */
final DialogUser dbsP = new DialogUser(false, this);
/** Databases panel. */
final BaseXBack databases = dbsP.getTablePanel();
/** Sessions/Databases panel. */
final BaseXBack sess = new BaseXBack();
/** Log panel. */
final BaseXBack logs = new BaseXBack();
/** Username textfield. */
final BaseXTextField loguser;
/** Disconnect button. */
final BaseXButton disconnect;
/** Refresh button. */
final BaseXButton refreshSess;
/** Indicates which tab is activated. */
int tab;
/** Context. */
private final Context ctx = gui.context;
/** Updates log file. */
private final BaseXButton refreshLog;
/** Stop button. */
private final BaseXButton stop;
/** Start button. */
private final BaseXButton start;
/** Connect button. */
private final BaseXButton connect;
/** Deletes log file. */
private final BaseXButton delete;
/** Deletes all log files. */
private final BaseXButton deleteAll;
/** Server host. */
private final BaseXTextField host;
/** Local server port. */
private final BaseXTextField ports;
/** Server port. */
private final BaseXTextField portc;
/** Current databases. */
private final BaseXEditor sese;
/** Current sessions. */
private final BaseXEditor sedb;
/** Log text. */
private final BaseXEditor logt;
/** Info label. */
private final BaseXLabel infoC;
/** Info label. */
private final BaseXLabel infoL;
/** Combobox for log files. */
private final BaseXCombo logc;
/** String for log dir. */
private final IOFile logd = ctx.mprop.dbpath(".logs");
/** ClientSession. */
private ClientSession cs;
/** Boolean for check is server is running. */
private boolean running;
/** Boolean for check if client is connected. */
private boolean connected;
/**
* Default constructor.
* @param main reference to the main window
*/
public DialogServer(final GUI main) {
super(main, S_SERVER_ADMIN);
databases.border(8);
tabs = new BaseXTabs(this);
/* Server panel. */
final BaseXBack conn = new BaseXBack();
tabs.add(S_CONNECT, conn);
tabs.add(USERS, user);
tabs.add(DATABASES, databases);
tabs.add(S_SESSIONS, sess);
tabs.add(S_LOCALLOGS, logs);
// server tab
conn.border(8).layout(new BorderLayout(0, 32));
start = new BaseXButton(START, this);
stop = new BaseXButton(STOP, this);
connect = new BaseXButton(CONNECT, this);
disconnect = new BaseXButton(DISCONNECT, this);
host = new BaseXTextField(ctx.mprop.get(MainProp.HOST), this);
host.addKeyListener(keys);
ports = new BaseXTextField(Integer.toString(
ctx.mprop.num(MainProp.SERVERPORT)), this);
ports.addKeyListener(keys);
portc = new BaseXTextField(Integer.toString(
ctx.mprop.num(MainProp.PORT)), this);
portc.addKeyListener(keys);
loguser = new BaseXTextField(gui.gprop.get(GUIProp.SERVERUSER), this);
loguser.addKeyListener(keys);
logpass = new BaseXPassword(main);
logpass.addKeyListener(keys);
infoC = new BaseXLabel(" ").border(12, 0, 0, 0);
BaseXBack p = new BaseXBack(new TableLayout(6, 1, 0, 0));
// local server panel
p.add(new BaseXLabel(S_LOCALSERVER + COLS, true, true));
BaseXBack pp = new BaseXBack(new TableLayout(2, 2, 8, 4)).border(
0, 0, 0, 0);
pp.add(new BaseXLabel(S_PORT + COLS));
pp.add(ports);
pp.add(new BaseXLabel());
BaseXBack ppp = new BaseXBack(new TableLayout(1, 2, 5, 0));
ppp.add(start);
ppp.add(stop);
pp.add(ppp);
p.add(pp);
p.add(new BaseXLabel());
p.add(new BaseXLabel(S_ADLOGIN + COLS, true, true).border(12, 0, 6, 0));
// login panel
pp = new BaseXBack(new TableLayout(5, 2, 8, 4));
pp.add(new BaseXLabel(USERNAME + COLS));
pp.add(loguser);
pp.add(new BaseXLabel(PASSWORD + COLS));
pp.add(logpass);
pp.add(new BaseXLabel(S_HOST + COLS));
pp.add(host);
pp.add(new BaseXLabel(S_PORT + COLS));
pp.add(portc);
pp.add(new BaseXLabel());
ppp = new BaseXBack(new TableLayout(1, 2, 5, 0));
ppp.add(connect);
ppp.add(disconnect);
pp.add(ppp);
p.add(pp);
p.add(infoC);
conn.add(p, BorderLayout.CENTER);
p = new BaseXBack(new TableLayout(2, 1));
BaseXLabel l = new BaseXLabel(S_INFO1);
l.setForeground(GUIConstants.DGRAY);
p.add(l);
l = new BaseXLabel(S_INFO2);
l.setForeground(GUIConstants.DGRAY);
p.add(l);
conn.add(p, BorderLayout.SOUTH);
// session tab
sess.border(8).layout(new BorderLayout());
sese = new BaseXEditor(false, this);
sese.setFont(start.getFont());
sedb = new BaseXEditor(false, this);
sedb.setFont(start.getFont());
refreshSess = new BaseXButton(REFRESH, this);
p = new BaseXBack(new GridLayout(2, 1, 0, 2));
pp = new BaseXBack(new BorderLayout());
pp.add(new BaseXLabel(S_SESSIONS + COLS, false, true), BorderLayout.NORTH);
pp.add(sese, BorderLayout.CENTER);
p.add(pp);
pp = new BaseXBack(new BorderLayout());
pp.add(new BaseXLabel(DATABASES + COLS, false, true), BorderLayout.NORTH);
pp.add(sedb, BorderLayout.CENTER);
p.add(pp);
sess.add(p, BorderLayout.CENTER);
p = new BaseXBack(new BorderLayout(0, 0));
p.add(refreshSess, BorderLayout.EAST);
sess.add(p, BorderLayout.SOUTH);
// logging tab
logs.border(8).layout(new BorderLayout());
delete = new BaseXButton(DELETE, this);
deleteAll = new BaseXButton(DELETE_ALL, this);
logc = new BaseXCombo(this);
logt = new BaseXEditor(false, this);
logt.setFont(start.getFont());
BaseXLayout.setHeight(logt, 100);
logt.border(5);
infoL = new BaseXLabel(" ").border(12, 0, 0, 0);
refreshLog = new BaseXButton(REFRESH, this);
p = new BaseXBack(new BorderLayout());
pp = new BaseXBack();
pp.add(logc);
pp.add(delete);
pp.add(deleteAll);
p.add(pp, BorderLayout.WEST);
logs.add(p, BorderLayout.NORTH);
logs.add(logt, BorderLayout.CENTER);
p = new BaseXBack(new BorderLayout(8, 0));
p.add(infoL, BorderLayout.WEST);
p.add(refreshLog, BorderLayout.EAST);
logs.add(p, BorderLayout.SOUTH);
set(tabs, BorderLayout.CENTER);
// test if server is running
running = ping(true);
tabs.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(final ChangeEvent evt) {
final BaseXTabs pane = (BaseXTabs) evt.getSource();
tab = pane.getSelectedIndex();
final Object o = pane.getSelectedComponent();
if(o == logs) refreshLog();
if(o == user) action(user);
if(o == databases) action(dbsP);
if(o == sess) action(refreshSess);
}
});
refreshLog();
action(null);
setResizable(true);
finish(null);
}
/**
* Checks if a server is running, ping like.
* @param local local/remote flag
* @return boolean success
*/
private boolean ping(final boolean local) {
return BaseXServer.ping(local ? LOCALHOST : ctx.mprop.get(MainProp.HOST),
ctx.mprop.num(local ? MainProp.SERVERPORT : MainProp.PORT));
}
@Override
public void action(final Object cmp) {
Msg icon = Msg.SUCCESS;
String msg = null;
String msg2 = null;
try {
if(cmp == start || cmp == ports) {
final int p = Integer.parseInt(ports.getText());
gui.setMain(MainProp.SERVERPORT, p);
if(host.getText().equals(LOCALHOST)) {
gui.setMain(MainProp.PORT, p);
portc.setText(ports.getText());
}
try {
BaseXServer.start(p);
msg = SRV_STARTED;
running = true;
} catch(final BaseXException ex) {
msg = ex.getMessage();
icon = Msg.ERROR;
}
} else if(cmp == stop) {
if(running) BaseXServer.stop(ctx.mprop.num(MainProp.SERVERPORT),
ctx.mprop.num(MainProp.EVENTPORT));
running = ping(true);
connected = connected && ping(false);
if(!connected) msg = SRV_STOPPED;
if(host.getText().equals(LOCALHOST)) logpass.setText("");
if(!connected) setTitle(S_SERVER_ADMIN);
} else if(cmp == connect || cmp == loguser || cmp == logpass ||
cmp == host || cmp == portc) {
gui.gprop.set(GUIProp.SERVERUSER, loguser.getText());
final String pw = new String(logpass.getPassword());
gui.setMain(MainProp.HOST, host.getText());
gui.setMain(MainProp.PORT, Integer.parseInt(portc.getText()));
cs = new ClientSession(ctx, gui.gprop.get(GUIProp.SERVERUSER), pw);
user.setSess(cs);
dbsP.setSess(cs);
connected = true;
setTitle(S_SERVER_ADMIN + LI + loguser.getText() + '@' +
host.getText() + COL + portc.getText());
msg = Util.info(S_CONNECTED, host.getText(), portc.getText());
refreshSess();
} else if(cmp == disconnect) {
cs.execute(new Exit());
connected = false;
logpass.setText("");
setTitle(S_SERVER_ADMIN);
msg = S_DISCONNECTED;
} else if(cmp == refreshSess) {
refreshSess();
} else if(cmp == refreshLog || cmp == logc) {
byte[] cont = Token.EMPTY;
if(logc.getSelectedIndex() != -1) {
final IOFile f = new IOFile(logd, logc.getSelectedItem().toString());
cont = f.read();
}
logt.setText(cont);
logt.scrollToEnd();
} else if(cmp == delete) {
final IOFile f = new IOFile(logd, logc.getSelectedItem().toString());
if(f.delete()) {
logc.setSelectedIndex(-1);
refreshLog();
} else {
msg2 = Util.info(FILE_NOT_DELETED_X, f.name());
icon = Msg.ERROR;
}
} else if(cmp == deleteAll) {
IOFile file = null;
for(int i = 0; i < logc.getItemCount(); ++i) {
final IOFile f = new IOFile(logd, logc.getItemAt(i).toString());
if(!f.delete()) file = f;
}
if(file != null) {
msg2 = Util.info(FILE_NOT_DELETED_X, file.name());
icon = Msg.ERROR;
}
logc.setSelectedIndex(-1);
refreshLog();
} else if(connected) {
if(tab == 1) user.action(cmp);
if(tab == 2) dbsP.action(cmp);
}
} catch(final Exception ex) {
icon = Msg.ERROR;
msg = Util.message(ex);
if(msg.equals(Util.info(PERM_NEEDED_X, CmdPerm.values()[4]))) {
try {
cs.execute(new Exit());
} catch(final IOException exx) {
Util.stack(exx);
}
}
}
final boolean valp = portc.getText().matches("[\\d]+") &&
Integer.parseInt(portc.getText()) <= 65535;
final boolean valpl = ports.getText().matches("[\\d]+") &&
Integer.parseInt(ports.getText()) <= 65535;
final boolean vallu = loguser.getText().matches("[\\w]*");
final boolean vallp = new String(
logpass.getPassword()).matches("[^ ;'\"]*");
final boolean valh = host.getText().matches("([\\w]+://)?[\\w.-]+");
if(msg == null && msg2 == null &&
!(valpl && valh && valp && vallu && vallp)) {
msg = Util.info(INVALID_X, !valpl ? S_LOCALPORT : !valh ? S_HOST :
!valp ? S_PORT : !vallu ? USERNAME : PASSWORD);
icon = Msg.WARN;
}
infoC.setText(msg, icon);
infoL.setText(msg2, icon);
ports.setEnabled(!running);
start.setEnabled(!running && valpl);
stop.setEnabled(running);
loguser.setEnabled(!connected);
logpass.setEnabled(!connected);
host.setEnabled(!connected);
portc.setEnabled(!connected);
connect.setEnabled(!connected && vallu && vallp && valh && valp &&
!loguser.getText().isEmpty() && logpass.getPassword().length != 0);
disconnect.setEnabled(connected);
tabs.setEnabledAt(1, connected);
tabs.setEnabledAt(2, connected);
tabs.setEnabledAt(3, connected);
tabs.setEnabledAt(4, running || logc.getItemCount() > 0);
refreshLog.setEnabled(logc.getSelectedIndex() != -1);
delete.setEnabled(logc.getSelectedIndex() != -1);
deleteAll.setEnabled(logc.getItemCount() > 0);
if(loguser.hasFocus()) {
logpass.setText("");
connect.setEnabled(false);
}
ctx.mprop.write();
}
/**
* Fills sessions/databases panel.
* @throws IOException I/O exception
*/
private void refreshSess() throws IOException {
sese.setText(Token.token(cs.execute(new ShowSessions())));
sedb.setText(Token.token(cs.execute(new ShowDatabases())));
}
/**
* Refreshes the log panel.
*/
void refreshLog() {
logc.removeAllItems();
final StringList sl = new StringList();
for(final IOFile s : logd.children()) {
final String name = s.name();
if(name.endsWith(".log")) sl.add(name);
}
sl.sort(false, false);
for(final String s : sl) logc.addItem(s);
action(refreshLog);
}
@Override
public void cancel() {
try {
if(connected) cs.execute(new Exit());
} catch(final IOException ex) {
Util.debug(ex);
}
super.cancel();
}
@Override
public void close() {
if(ok) super.close();
}
}