/**
* diqube: Distributed Query Base.
*
* Copyright (C) 2015 Bastian Gloeckle
*
* This file is part of diqube.
*
* diqube is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diqube.tool.im;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
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.diqube.remote.query.thrift.IdentityService;
import org.diqube.tool.ToolFunction;
import org.diqube.tool.ToolFunctionName;
import org.diqube.tool.info.Info;
import org.diqube.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.reflect.ClassPath;
import com.google.common.reflect.ClassPath.ClassInfo;
/**
* Tool function that interacts with {@link IdentityService}.
*
* @author Bastian Gloeckle
*/
@ToolFunctionName(IdentityToolFunction.FUNCTION_NAME)
public class IdentityToolFunction implements ToolFunction {
public static final Logger logger = LoggerFactory.getLogger(IdentityToolFunction.class);
private static final String BASE_PKG = "org.diqube.tool.im";
public static final String FUNCTION_NAME = "im";
public static final String OPT_HELP = "h";
public static final String OPT_ACTUAL_FUNCTION = "f";
public static final String OPT_LOGIN_USER = "lu";
public static final String OPT_LOGIN_PASSWORD = "lp";
public static final String OPT_PARAM_USER = "u";
public static final String OPT_PARAM_PASSWORD = "p";
public static final String OPT_PARAM_PERMISSION = "a";
public static final String OPT_PARAM_PERMISSION_OBJECT = "o";
public static final String OPT_PARAM_EMAIL = "e";
public static final String OPT_SERVER = "s";
private Map<String, Pair<AbstractActualIdentityToolFunction, IsActualIdentityToolFunction>> actualFunctions;
@Override
public void execute(String[] args) {
actualFunctions = loadActualFunctions();
Options cliOpt = createCliOptions();
CommandLineParser parser = new DefaultParser();
CommandLine cmd = null;
boolean showHelp = false;
String actualFunctionNameForHelp = null;
try {
cmd = parser.parse(cliOpt, args);
if (cmd.hasOption(OPT_HELP)) {
showHelp = true;
actualFunctionNameForHelp = cmd.getOptionValue(OPT_HELP);
}
} catch (ParseException e) {
logger.error(e.getMessage());
showHelp = true;
// check if there is a detailed -h option
try {
Options helpCliOptions = createCliOptionsOnlyHelp();
cmd = new DefaultParser().parse(helpCliOptions, args);
if (cmd.hasOption(OPT_HELP)) {
showHelp = true;
actualFunctionNameForHelp = cmd.getOptionValue(OPT_HELP);
}
} catch (ParseException e2) {
// swallow, we show help anyway.
}
}
if (showHelp) {
if (actualFunctionNameForHelp != null) {
if (actualFunctions.containsKey(actualFunctionNameForHelp)) {
System.out.println("Help for function '" + actualFunctionNameForHelp + "':");
System.out.println();
System.out.println(actualFunctions.get(actualFunctionNameForHelp).getRight().shortDescription());
return;
}
System.out.println("Unknown function: " + actualFunctionNameForHelp);
}
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp(Info.FUNCTION_NAME + " [options]",
"\nInteracts with the identity service of a diqube server.\n\n", cliOpt, "");
return;
}
String function = cmd.getOptionValue(OPT_ACTUAL_FUNCTION);
String loginUser = cmd.getOptionValue(OPT_LOGIN_USER);
String loginPassword = cmd.getOptionValue(OPT_LOGIN_PASSWORD);
String paramUser = cmd.getOptionValue(OPT_PARAM_USER);
String paramPassword = cmd.getOptionValue(OPT_PARAM_PASSWORD);
String paramPermission = cmd.getOptionValue(OPT_PARAM_PERMISSION);
String paramPermissionObject = cmd.getOptionValue(OPT_PARAM_PERMISSION_OBJECT);
String paramEmail = cmd.getOptionValue(OPT_PARAM_EMAIL);
String server = cmd.getOptionValue(OPT_SERVER);
if (!actualFunctions.containsKey(function)) {
logger.error("Unknown function '{}'", function);
return;
}
AbstractActualIdentityToolFunction fn = actualFunctions.get(function).getLeft();
fn.initializeGeneral(server, loginUser, loginPassword);
fn.initializeOptionalParams(paramUser, paramPassword, paramPermission, paramPermissionObject, paramEmail);
logger.info("Executing function '{}'...", function);
fn.execute();
logger.info("Function executed successfully.", function);
}
private Map<String, Pair<AbstractActualIdentityToolFunction, IsActualIdentityToolFunction>> loadActualFunctions() {
try {
Collection<ClassInfo> classInfos =
ClassPath.from(getClass().getClassLoader()).getTopLevelClassesRecursive(BASE_PKG);
Map<String, Pair<AbstractActualIdentityToolFunction, IsActualIdentityToolFunction>> toolFunctions =
new HashMap<>();
for (ClassInfo classInfo : classInfos) {
Class<?> clazz = classInfo.load();
IsActualIdentityToolFunction isActualIdentityToolFunctionAnnotation =
clazz.getAnnotation(IsActualIdentityToolFunction.class);
if (isActualIdentityToolFunctionAnnotation != null) {
AbstractActualIdentityToolFunction functionInstance =
(AbstractActualIdentityToolFunction) clazz.newInstance();
toolFunctions.put(isActualIdentityToolFunctionAnnotation.identityFunctionName(),
new Pair<>(functionInstance, isActualIdentityToolFunctionAnnotation));
}
}
return toolFunctions;
} catch (IOException | InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private Options createCliOptions() {
Options res = new Options();
res.addOption(Option.builder(OPT_ACTUAL_FUNCTION).longOpt("function").numberOfArgs(1).argName("name")
.desc("Name of the function to execute on the identity service (required). One of the following: "
+ actualFunctions.keySet())
.required().build());
res.addOption(Option.builder(OPT_SERVER).longOpt("server").numberOfArgs(1).argName("ip:port")
.desc("Server address of a running diqube server.").required().build());
res.addOption(Option.builder(OPT_LOGIN_USER).longOpt("login-user").numberOfArgs(1).argName("name")
.desc("Username to use for authentication at the identity service (required).").required().build());
res.addOption(Option.builder(OPT_LOGIN_PASSWORD).longOpt("login-password").numberOfArgs(1).argName("password")
.desc("Password to use for authentication at the identity service (required).").required().build());
res.addOption(Option.builder(OPT_PARAM_USER).longOpt("user").numberOfArgs(1).argName("name")
.desc("Username to use as parameter to the function.").build());
res.addOption(Option.builder(OPT_PARAM_PASSWORD).longOpt("password").numberOfArgs(1).argName("password")
.desc("Password to use as parameter to the function.").build());
res.addOption(Option.builder(OPT_PARAM_PERMISSION).longOpt("permission").numberOfArgs(1).argName("name")
.desc("Permission to use as parameter to the function.").build());
res.addOption(Option.builder(OPT_PARAM_PERMISSION_OBJECT).longOpt("object").numberOfArgs(1).argName("name")
.desc("Permission object to use as parameter to the function.").build());
res.addOption(Option.builder(OPT_PARAM_EMAIL).longOpt("email").numberOfArgs(1).argName("address")
.desc("E-mail address to use as parameter to the function.").build());
addHelpOption(res);
return res;
}
private void addHelpOption(Options res) {
res.addOption(Option.builder(OPT_HELP).longOpt("help").numberOfArgs(1).argName("function name")
.desc("Show this help or the help of a specific function (see flag '" + OPT_ACTUAL_FUNCTION + "').").build());
}
private Options createCliOptionsOnlyHelp() {
Options res = new Options();
addHelpOption(res);
return res;
}
}