/*
* $Id: ServerControl.java,v 1.20 2002/09/16 08:05:06 jkl Exp $
*
* Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
*
* Use is subject to license terms, as defined in
* Anvil Sofware License, Version 1.1. See LICENSE
* file, or http://njet.org/license-1.1.txt
*/
package anvil.server;
import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.net.ServerSocket;
import java.net.InetAddress;
import java.util.Calendar;
import java.util.StringTokenizer;
/**
* class ServerControl
*
* @author: Jani Lehtim�ki
*/
public class ServerControl extends Thread
{
static {
anvil.core.Any.class.getName();
}
private File _config;
private File _configGen;
private Server _server;
private int _port = 7077;
private boolean _listen = false;
public ServerControl(String config)
{
setConfig(config);
setName("ServerControl");
}
protected void setConfig(String config)
{
_config = new File(config);
_configGen = new File(config + ".generated");
}
public File getConfigFile()
{
return _config;
}
public File getGeneratedConfigFile()
{
return _configGen;
}
public boolean isStarted()
{
return _server != null;
}
public void listen(int port)
{
_listen = true;
_port = port;
this.start();
}
public void listen()
{
_listen = true;
AdminClient client = new AdminClient(System.in, System.out);
client.run();
}
public synchronized Server getServer() throws IOException
{
if (_server == null) {
start(System.out);
}
return _server;
}
public synchronized void start(PrintStream out) throws IOException
{
if (_server == null) {
File source = _configGen;
if (!source.exists() || !source.canRead()) {
source = _config;
}
out.println("server starting up: "+source);
ConfigReader reader = new ConfigReader(this, source);
Server server = reader.parse();
server.start();
_server = server;
} else {
throw new IllegalStateException("Server already started");
}
}
public synchronized void stop(PrintStream out)
{
if (_server != null) {
try {
_server.stop();
} finally {
_server = null;
}
out.println("server stopped.");
} else {
throw new IllegalStateException("Server is not started");
}
}
public synchronized void reread(PrintStream out) throws IOException
{
out.println("server reconfiguring: "+_config);
if (_server != null) {
stop(out);
}
start(out);
}
public synchronized void reread(PrintStream out, String config) throws IOException
{
out.println("server reconfiguring: "+config);
if (_server != null) {
stop(out);
}
setConfig(config);
start(out);
}
public synchronized void write() throws IOException
{
if (_server != null) {
ConfigWriter writer = new ConfigWriter();
writer.write(_configGen, _server);
} else {
throw new IllegalStateException("Server is not started");
}
}
public void run()
{
try {
int count = 0;
ServerSocket serversocket = new ServerSocket(_port);
serversocket.setSoTimeout(2000);
anvil.Log.log().info("Admininstration end point created at "+_port);
while(_listen) {
try {
Socket socket = serversocket.accept();
TelnetAdminClient adminclient = new TelnetAdminClient(socket);
adminclient.setName("Admin-"+(count++));
adminclient.start();
} catch (InterruptedIOException e) {
}
}
serversocket.close();
} catch (Throwable t) {
anvil.Log.log().error(t);
}
}
public String prompt(Configurable config)
{
/*Calendar calendar = Calendar.getInstance();
StringBuffer buf = new StringBuffer();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int min = calendar.get(Calendar.MINUTE);
int sec = calendar.get(Calendar.SECOND);
buf.append('[');
if (hour<10) {
buf.append('0');
}
buf.append(hour);
buf.append(':');
if (min<10) {
buf.append('0');
}
buf.append(min);
buf.append('.');
if (sec<10) {
buf.append('0');
}
buf.append(sec);
buf.append("server% ");
*/
if (config == null) {
return "<server stopped> ";
} else {
return "<"+config+"> ";
}
}
public static void main(String[] args)
{
if (args.length == 0) {
System.out.println("usage: server [-d] [-p admin_port] [config]\n\n");
return;
}
try {
String config = "./anvil.properties";
boolean detach = false;
int port = 7077;
int n = args.length;
int i = 0;
while (i<n) {
String s = args[i++];
if (s.equals("-p")) {
if (i<n) {
try {
port = Integer.parseInt(args[i++]);
} catch (NumberFormatException e) {
}
}
} else if (s.equals("-d")) {
detach = true;
} else {
config = s;
}
}
System.out.println("anvil "+anvil.Version.getFullVersion());
ServerControl control = new ServerControl(config);
control.start(System.out);
if (detach) {
control.listen(port);
} else {
control.listen();
if (control.isStarted()) {
control.stop(System.out);
}
}
} catch (Throwable t) {
t.printStackTrace();
}
}
public class TelnetAdminClient extends AdminClient
{
private Socket _socket;
public TelnetAdminClient(Socket socket) throws IOException
{
super(socket.getInputStream(), socket.getOutputStream());
_socket = socket;
}
public void run()
{
InetAddress address = _socket.getInetAddress();
anvil.Log.log().info("Admininstration connection from "+address.getHostName());
super.run();
try {
_socket.close();
} catch (IOException e) {
anvil.Log.log().error(e);
}
anvil.Log.log().info("Admininstration connection from "+address.getHostName()+" closed");
}
}
public class AdminClient extends Thread
{
protected InputStream _input;
protected OutputStream _output;
protected Configurable _self;
public AdminClient(InputStream input, OutputStream output)
{
super();
_input = input;
_output = output;
}
public void run()
{
try {
LineNumberReader reader = new LineNumberReader(new InputStreamReader(_input));
PrintStream out = new PrintStream(_output);
out.println("** Anvil "+anvil.Version.getFullVersion());
out.println("** Copyright (c) 1999-2002, Njet Communications ltd. All rights reserved.");
out.println("** Type 'help' for help");
_self = _server;
while(true) {
if (out.checkError()) {
break;
}
out.print(prompt(_self));
String line = reader.readLine();
if (line == null) {
break;
}
try {
if (action(out, line)) {
break;
}
} catch (Throwable t) {
t.printStackTrace(out);
}
}
} catch (Throwable t) {
anvil.Log.log().error(t);
}
}
public boolean action(PrintStream out, String command) throws IOException
{
synchronized(ServerControl.this) {
if (command == null) {
return false;
}
String[] params = Preferences.parseValues(command);
if (params.length == 0) {
return false;
}
String action = params[0];
if (action.equalsIgnoreCase("status")) {
if (isStarted()) {
out.println("server is started");
} else {
out.println("server is not started");
}
out.println("config: "+_config);
out.println("generated config: "+_config);
Runtime runtime = Runtime.getRuntime();
long total = runtime.totalMemory();
long free = runtime.freeMemory();
out.println("total memory: "+(total/1024)+" kB");
out.println("used memory: "+((total-free)/1024)+" kB");
out.println("free memory: "+(free/1024)+" kB");
if (_listen) {
out.println("administration running at port: "+_port);
}
} if (action.equalsIgnoreCase("gc")) {
out.println("Running gc...");
Runtime.getRuntime().gc();
out.println("...done!");
} if (action.equalsIgnoreCase("start")) {
if (!isStarted()) {
ServerControl.this.start(out);
_self = _server;
} else {
out.println("server is already started");
}
} if (action.equalsIgnoreCase("restart")) {
if (isStarted()) {
ServerControl.this.stop(out);
}
ServerControl.this.start(out);
_self = _server;
} else if (action.equalsIgnoreCase("stop")) {
if (isStarted()) {
ServerControl.this.stop(out);
_self = null;
} else {
out.println("server is not started");
}
} else if (action.equalsIgnoreCase("shutdown")) {
out.println("shutting down...");
if (isStarted()) {
ServerControl.this.stop(out);
}
if (_listen) {
_listen = false;
ServerControl.this.interrupt();
}
return true;
} else if (action.equalsIgnoreCase("exit")) {
return true;
} else if (action.equalsIgnoreCase("reread")) {
reread(out);
_self = _server;
} else if (action.equalsIgnoreCase("read")) {
if (params.length >= 2) {
reread(out, params[1]);
} else {
out.println("config file not given");
}
_self = _server;
} else if (action.startsWith("config")) {
if (isStarted()) {
ConfigWriter writer = new ConfigWriter();
writer.write(out, _self);
} else {
out.println("server is not started");
}
} else if (action.startsWith("dump")) {
anvil.script.Context.dumpStacks(out);
} else if (action.startsWith("ls")) {
if (isStarted()) {
Configurable[] c = _self.getConfigurations();
if (c != null && c.length > 0) {
for(int i=0; i<c.length; i++) {
out.print(i);
out.print(": ");
out.println(c[i]);
}
}
} else {
out.println("server is not started");
}
} else if (action.startsWith("pwd")) {
if (isStarted()) {
Configurable c = _self;
while(c != null) {
out.println(c);
c = c.getParent();
}
} else {
out.println("server is not started");
}
} else if (action.startsWith("cd")) {
if (isStarted()) {
if (params.length >= 2) {
String param = params[1];
if (param.equals("..")) {
Configurable c = _self.getParent();
if (c != null) {
_self = c;
}
} else {
try {
int index = Integer.parseInt(param);
Configurable[] c = _self.getConfigurations();
if (index>=0 && index<c.length) {
_self = c[index];
} else {
out.println("parameter '"+param+"' out of range");
}
} catch (NumberFormatException e) {
out.println("invalid parameter '"+param+"' for cd");
}
}
} else {
out.println("cd requires parameter");
}
} else {
out.println("server is not started");
}
} else if (action.startsWith("set")) {
if (isStarted()) {
if (params.length == 3) {
if (!_self.setPreference(params[1], params[2])) {
out.println("failed");
}
} else if (params.length == 2) {
if (!_self.setPreference(params[1], null)) {
out.println("failed");
}
} else {
String[] s = _self.getPreferences();
int n = s.length;
int i = 0;
while(i<n) {
out.print("[");
out.print(s[i+1]);
out.print("] ");
out.print(s[i]);
out.print(" = ");
Object value = _self.getPreference(s[i]);
if (value != null) {
out.print("'");
out.print(value);
out.println("'");
} else {
out.println("<empty>");
}
i += 2;
}
s = _self.getAdditionalPreferenceNames();
if (s != null) {
n = s.length;
for(i=0; i<n; i++) {
out.print("[string] ");
out.print(s[i]);
out.print(" = ");
Object value = _self.getPreference(s[i]);
if (value != null) {
out.print("'");
out.print(value);
out.println("'");
} else {
out.println("<empty>");
}
}
}
}
} else {
out.println("server is not started");
}
} else if (action.equalsIgnoreCase("help")) {
out.println("commands:");
out.println("- status shows server status");
out.println("- gc triggers garbage collection");
out.println("- exit exits from admin client");
out.println("- start starts the server");
out.println("- stop stops the server");
out.println("- restart restarts the servers");
out.println("- reread rereads server's config");
out.println("- read <config> reads config from given file");
out.println("- shutdown shuts the server down");
out.println("- dump dumps the current execution stacks");
out.println();
out.println("these cmmands below target to current 'directory':");
out.println("- pwd print current directory");
out.println("- ls lists contents");
out.println("- cd <index> moves to <index> as given by 'ls'");
out.println("- cd .. moves up");
out.println("- config prints configuration");
out.println("- set lists preferences");
out.println("- set <name> removes given preference");
out.println("- set <name> <value> set preference <name> to <value>");
}
out.println();
return false;
}
}
}
}