blob: 227099a389630b7394a58bbd1d2ac6248e1bba6b [file] [log] [blame]
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
package org.apache.james.cli;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.time.StopWatch;
import org.apache.james.adapter.mailbox.SerializableQuota;
import org.apache.james.cli.exceptions.InvalidArgumentNumberException;
import org.apache.james.cli.exceptions.InvalidPortException;
import org.apache.james.cli.exceptions.JamesCliException;
import org.apache.james.cli.exceptions.MissingCommandException;
import org.apache.james.cli.exceptions.UnrecognizedCommandException;
import org.apache.james.cli.probe.ServerProbe;
import org.apache.james.cli.probe.impl.JmxServerProbe;
import org.apache.james.cli.type.CmdType;
import org.apache.james.cli.utils.ValueWithUnit;
import org.apache.james.mailbox.model.Quota;
import org.apache.james.rrt.lib.Mappings;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
/**
* Command line utility for managing various aspect of the James server.
*/
public class ServerCmd {
public static final String HOST_OPT_LONG = "host";
public static final String HOST_OPT_SHORT = "h";
public static final String PORT_OPT_LONG = "port";
public static final String PORT_OPT_SHORT = "p";
private static final int DEFAULT_PORT = 9999;
private static Options createOptions() {
Options options = new Options();
Option optHost = new Option(HOST_OPT_SHORT, HOST_OPT_LONG, true, "node hostname or ip address");
optHost.setRequired(true);
options.addOption(optHost);
options.addOption(PORT_OPT_SHORT, PORT_OPT_LONG, true, "remote jmx agent port number");
return options;
}
private final ServerProbe probe;
public ServerCmd(ServerProbe probe) {
this.probe = probe;
}
/**
* Main method to initialize the class.
*
* @param args Command-line arguments.
*/
public static void main(String[] args) {
try {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
CommandLine cmd = parseCommandLine(args);
CmdType cmdType =new ServerCmd(new JmxServerProbe(cmd.getOptionValue(HOST_OPT_LONG), getPort(cmd)))
.executeCommandLine(cmd);
stopWatch.split();
print(new String[] { Joiner.on(' ')
.join(cmdType.getCommand(), "command executed sucessfully in", stopWatch.getSplitTime(), "ms.")},
System.out);
stopWatch.stop();
System.exit(0);
} catch (JamesCliException e) {
failWithMessage(e.getMessage());
} catch (ParseException e) {
failWithMessage("Error parsing command line : " + e.getMessage());
} catch (IOException ioe) {
failWithMessage("Error connecting to remote JMX agent : " + ioe.getMessage());
} catch (Exception e) {
failWithMessage("Error while executing command:" + e.getMessage());
}
}
@VisibleForTesting
static CommandLine parseCommandLine(String[] args) throws ParseException {
CommandLineParser parser = new PosixParser();
CommandLine commandLine = parser.parse(createOptions(), args);
if (commandLine.getArgs().length < 1) {
throw new MissingCommandException();
}
return commandLine;
}
@VisibleForTesting
static int getPort(CommandLine cmd) throws ParseException {
String portNum = cmd.getOptionValue(PORT_OPT_LONG);
if (portNum != null) {
try {
return validatePortNumber(Integer.parseInt(portNum));
} catch (NumberFormatException e) {
throw new ParseException("Port must be a number");
}
}
return DEFAULT_PORT;
}
private static int validatePortNumber(int portNumber) {
if (portNumber < 1 || portNumber > 65535) {
throw new InvalidPortException(portNumber);
}
return portNumber;
}
private static void failWithMessage(String s) {
System.err.println(s);
printUsage();
System.exit(1);
}
@VisibleForTesting
CmdType executeCommandLine(CommandLine cmd) throws Exception {
String[] arguments = cmd.getArgs();
String cmdName = arguments[0];
CmdType cmdType = CmdType.lookup(cmdName);
if (cmdType == null) {
throw new UnrecognizedCommandException(cmdName);
}
if (! cmdType.hasCorrectArguments(arguments.length)) {
throw new InvalidArgumentNumberException(cmdType, arguments.length);
}
executeCommand(arguments, cmdType);
return cmdType;
}
private void executeCommand(String[] arguments, CmdType cmdType) throws Exception {
switch (cmdType) {
case ADDUSER:
probe.addUser(arguments[1], arguments[2]);
break;
case REMOVEUSER:
probe.removeUser(arguments[1]);
break;
case LISTUSERS:
print(probe.listUsers(), System.out);
break;
case ADDDOMAIN:
probe.addDomain(arguments[1]);
break;
case REMOVEDOMAIN:
probe.removeDomain(arguments[1]);
break;
case CONTAINSDOMAIN:
if (probe.containsDomain(arguments[1])) {
System.out.println(arguments[1] + " exists");
} else {
System.out.println(arguments[1] + " does not exists");
}
break;
case LISTDOMAINS:
print(probe.listDomains(), System.out);
break;
case LISTMAPPINGS:
print(probe.listMappings(), System.out);
break;
case LISTUSERDOMAINMAPPINGS:
Mappings userDomainMappings = probe.listUserDomainMappings(arguments[1], arguments[2]);
print(userDomainMappings.asStrings(), System.out);
break;
case ADDADDRESSMAPPING:
probe.addAddressMapping(arguments[1], arguments[2], arguments[3]);
break;
case REMOVEADDRESSMAPPING:
probe.removeAddressMapping(arguments[1], arguments[2], arguments[3]);
break;
case ADDREGEXMAPPING:
probe.addRegexMapping(arguments[1], arguments[2], arguments[3]);
break;
case REMOVEREGEXMAPPING:
probe.removeRegexMapping(arguments[1], arguments[2], arguments[3]);
break;
case SETPASSWORD:
probe.setPassword(arguments[1], arguments[2]);
break;
case COPYMAILBOX:
probe.copyMailbox(arguments[1], arguments[2]);
break;
case DELETEUSERMAILBOXES:
probe.deleteUserMailboxesNames(arguments[1]);
break;
case CREATEMAILBOX:
probe.createMailbox(arguments[1], arguments[2], arguments[3]);
break;
case LISTUSERMAILBOXES:
Collection<String> mailboxes = probe.listUserMailboxes(arguments[1]);
print(mailboxes.toArray(new String[0]), System.out);
break;
case DELETEMAILBOX:
probe.deleteMailbox(arguments[1], arguments[2], arguments[3]);
break;
case GETSTORAGEQUOTA:
printStorageQuota(arguments[1], probe.getStorageQuota(arguments[1]));
break;
case GETMESSAGECOUNTQUOTA:
printMessageQuota(arguments[1], probe.getMessageCountQuota(arguments[1]));
break;
case GETQUOTAROOT:
System.out.println("Quota Root : " + probe.getQuotaRoot(arguments[1], arguments[2], arguments[3]));
break;
case GETMAXSTORAGEQUOTA:
System.out.println("Storage space allowed for Quota Root "
+ arguments[1]
+ " : "
+ formatStorageValue(probe.getMaxStorage(arguments[1])));
break;
case GETMAXMESSAGECOUNTQUOTA:
System.out.println("MailboxMessage count allowed for Quota Root " + arguments[1] + " : " + formatMessageValue(probe.getMaxMessageCount(arguments[1])));
break;
case SETMAXSTORAGEQUOTA:
probe.setMaxStorage(arguments[1], ValueWithUnit.parse(arguments[2]).getConvertedValue());
break;
case SETMAXMESSAGECOUNTQUOTA:
probe.setMaxMessageCount(arguments[1], Long.parseLong(arguments[2]));
break;
case SETDEFAULTMAXSTORAGEQUOTA:
probe.setDefaultMaxStorage(ValueWithUnit.parse(arguments[1]).getConvertedValue());
break;
case SETDEFAULTMAXMESSAGECOUNTQUOTA:
probe.setDefaultMaxMessageCount(Long.parseLong(arguments[1]));
break;
case GETDEFAULTMAXSTORAGEQUOTA:
System.out.println("Default Maximum Storage Quota : " + formatStorageValue(probe.getDefaultMaxStorage()));
break;
case GETDEFAULTMAXMESSAGECOUNTQUOTA:
System.out.println("Default Maximum message count Quota : " + formatMessageValue(probe.getDefaultMaxMessageCount()));
break;
case REINDEXMAILBOX:
probe.reIndexMailbox(arguments[1], arguments[2], arguments[3]);
break;
case REINDEXALL:
probe.reIndexAll();
break;
case SETSIEVEQUOTA:
probe.setSieveQuota(ValueWithUnit.parse(arguments[1]).getConvertedValue());
break;
case SETSIEVEUSERQUOTA:
probe.setSieveQuota(arguments[1], ValueWithUnit.parse(arguments[2]).getConvertedValue());
break;
case GETSIEVEQUOTA:
System.out.println("Storage space allowed for Sieve scripts by default : "
+ formatStorageValue(probe.getSieveQuota()));
break;
case GETSIEVEUSERQUOTA:
System.out.println("Storage space allowed for "
+ arguments[1]
+ " Sieve scripts : "
+ formatStorageValue(probe.getSieveQuota(arguments[1])));
break;
case REMOVESIEVEQUOTA:
probe.removeSieveQuota();
break;
case REMOVESIEVEUSERQUOTA:
probe.removeSieveQuota(arguments[1]);
break;
default:
throw new UnrecognizedCommandException(cmdType.getCommand());
}
}
private static void print(String[] data, PrintStream out) {
print(Arrays.asList(data), out);
}
private static void print(Iterable<String> data, PrintStream out) {
if (data != null) {
for (String u : data) {
out.println(u);
}
out.println(Joiner.on('\n').join(data));
}
}
private void printStorageQuota(String quotaRootString, SerializableQuota quota) {
System.out.println(String.format("Storage quota for %s is : %s / %s",
quotaRootString,
formatStorageValue(quota.getUsed()),
formatStorageValue(quota.getMax())));
}
private void printMessageQuota(String quotaRootString, SerializableQuota quota) {
System.out.println(String.format("MailboxMessage count quota for %s is : %s / %s",
quotaRootString,
formatMessageValue(quota.getUsed()),
formatMessageValue(quota.getMax())));
}
private String formatStorageValue(long value) {
if (value == Quota.UNKNOWN) {
return ValueWithUnit.UNKNOWN;
}
if (value == Quota.UNLIMITED) {
return ValueWithUnit.UNLIMITED;
}
return FileUtils.byteCountToDisplaySize(value);
}
private String formatMessageValue(long value) {
if (value == Quota.UNKNOWN) {
return ValueWithUnit.UNKNOWN;
}
if (value == Quota.UNLIMITED) {
return ValueWithUnit.UNLIMITED;
}
return String.valueOf(value);
}
private void print(Map<String, Mappings> map, PrintStream out) {
if (map != null) {
for (Entry<String, Mappings> entry : map.entrySet()) {
out.println(entry.getKey() + '=' + entry.getValue().serialize());
}
out.println();
}
}
private static void printUsage() {
StringBuilder footerBuilder = new StringBuilder();
for (CmdType cmdType : CmdType.values()) {
footerBuilder.append(cmdType.getUsage()).append("\n");
}
new HelpFormatter().printHelp(
String.format("java %s --host <arg> <command>%n", ServerCmd.class.getName()),
"",
createOptions(),
footerBuilder.toString());
}
}