Java tutorial
/* * 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 com.aliyun.openservices.odps.console.utils; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.Options; import com.aliyun.odps.OdpsDeprecatedLogger; import com.aliyun.odps.utils.StringUtils; import com.aliyun.openservices.odps.console.ExecutionContext; import com.aliyun.openservices.odps.console.ODPSConsoleException; import com.aliyun.openservices.odps.console.commands.AbstractCommand; import com.aliyun.openservices.odps.console.commands.CompositeCommand; import com.aliyun.openservices.odps.console.commands.InstancePriorityCommand; import com.aliyun.openservices.odps.console.commands.InteractiveCommand; import com.aliyun.openservices.odps.console.commands.LoginCommand; import com.aliyun.openservices.odps.console.commands.UseProjectCommand; import com.aliyun.openservices.odps.console.constants.ODPSConsoleConstants; import com.aliyun.openservices.odps.console.utils.antlr.AntlrObject; /** * ?????? * * @author shuman.gansm */ public class CommandParserUtils { private static final String COMMAND_PACKAGE = "com.aliyun.openservices.odps.console.commands"; /** * ??CommandCommand?? * ?ExecuteCommand-e?-e??ExecuteCommand? */ private static final String[] COMMANDLINE_COMMANDS = new String[] { "SetEndpointCommand", "LoginCommand", "UseProjectCommand", "DryRunCommand", "MachineReadableCommand", "FinanceJsonCommand", "AsyncModeCommand", "InstancePriorityCommand", "SkipCommand", "SetRetryCommand", "InteractiveCommand", "ExecuteCommand", "HelpCommand", "ShowVersionCommand" }; /** * ??CommandCommand?? */ private static final String[] INTERACTIVE_COMMANDS = new String[] { "QuitCommand", "HelpCommand", "UseProjectCommand", "SetCommand", "ExportMetaCommand", "ShowTablesCommand", // list tables "ShowPartitionsCommand", // list partitions "DescribeCommand", // describe table metas "UnSetCommand" }; private static final String HELP_TAGS_FIELD = "HELP_TAGS"; private static final String HELP_PRINT_METHOD = "printUsage"; public static String[] getCommandTokens(String cmd) throws ODPSConsoleException { AntlrObject antlr = new AntlrObject(cmd); String[] args = antlr.getTokenStringArray(); if (args == null) { throw new ODPSConsoleException("Invalid parameters - Generic options must be specified."); } return args; } public static CommandLine getCommandLine(String[] args, Options opts) throws ODPSConsoleException { CommandLineParser clp = new GnuParser(); CommandLine cl; try { cl = clp.parse(opts, args, false); } catch (Exception e) { throw new ODPSConsoleException("Unknown exception from client - " + e.getMessage(), e); } return cl; } public static CommandLine getCommandLine(String cmd, Options opts) throws ODPSConsoleException { return getCommandLine(getCommandTokens(cmd), opts); } /** * ??? * * @param args * @return * @throws ODPSConsoleException */ public static AbstractCommand parseOptions(String args[], ExecutionContext sessionContext) throws ODPSConsoleException { // option listoptionlist???? List<String> optionList = new LinkedList<String>(Arrays.asList(args)); // ??-e"", --project=??option optionList = populateOptions(optionList); removeHook(optionList, sessionContext); // commandList?parse?command? List<AbstractCommand> commandList = new LinkedList<AbstractCommand>(); parseCommandLineCommand(commandList, optionList, sessionContext); // ????, ?? if (optionList.size() > 0) { throw new ODPSConsoleException(ODPSConsoleConstants.BAD_COMMAND); } boolean hasLoginCommand = false; for (AbstractCommand command : commandList) { if (command instanceof LoginCommand) { hasLoginCommand = true; break; } } // account_providerlogincomandlogincomand? if (!hasLoginCommand && sessionContext.getAccountProvider() != null) { commandList.add(0, new LoginCommand(sessionContext.getAccountProvider(), sessionContext.getAccessId(), null, null, "--account_provider", sessionContext)); } checkUseProject(commandList, sessionContext); CompositeCommand compositeCommand = new CompositeCommand(commandList, "", sessionContext); return compositeCommand; } public static void removeHook(List<String> optionList, ExecutionContext sessionContext) { // hook?command??optioncontext if (optionList.contains("--enablehook")) { if (optionList.indexOf("--enablehook") + 1 < optionList.size()) { int index = optionList.indexOf("--enablehook"); // command String hook = optionList.get(index + 1); // --enablehook ?? optionList.remove(optionList.indexOf("--enablehook")); optionList.remove(optionList.indexOf(hook)); if (!Boolean.valueOf(hook)) { sessionContext.setOdpsHooks(null); } } } } /** * ?? * * @param commandLines * @return * @throws ODPSConsoleException */ public static AbstractCommand parseCommand(String commandLines, ExecutionContext sessionContext) throws ODPSConsoleException { commandLines = commandLines.trim(); if (commandLines.equals("")) { throw new ODPSConsoleException(ODPSConsoleConstants.INVALID_PARAMETER_E); } int index = commandLines.lastIndexOf(";"); if (index != commandLines.length() - 1) { throw new ODPSConsoleException(ODPSConsoleConstants.COMMAND_END_WITH); } OdpsDeprecatedLogger.getDeprecatedCalls().put("USER_COMMANDS :" + commandLines, 1L); // ?? List<String> commandLinelist = new AntlrObject(commandLines).splitCommands(); // SqlLinesParser??--????,?,query?command? if (commandLinelist.size() == 0 && !commandLines.trim().startsWith("--")) { commandLinelist.add(commandLines.substring(0, index)); } // List<AbstractCommand> odpsCommandList = new LinkedList<AbstractCommand>(); // query number int i = 0; // commandskip int step = sessionContext.getStep(); for (String command : commandLinelist) { i++; if (step > i) { continue; } command = command.trim(); // for null command if (command.equals("")) { continue; } parseInteractiveCommand(odpsCommandList, command, sessionContext, i); } // query if (step > i) { throw new ODPSConsoleException( "[Error] invalid NUM for option k, total query count inlcude empty query: " + i); } if (odpsCommandList.size() == 1) { return odpsCommandList.get(0); } else { CompositeCommand compositeCommand = new CompositeCommand(odpsCommandList, "", sessionContext); return compositeCommand; } } private static void checkUseProject(List<AbstractCommand> commandList, ExecutionContext sessionContext) throws ODPSConsoleException { if (sessionContext.getProjectName() == null || sessionContext.getProjectName().equals("")) { return; } boolean useProjectFlag = false; for (AbstractCommand command : commandList) { if (command instanceof UseProjectCommand || command instanceof InteractiveCommand) { useProjectFlag = true; } } if (!useProjectFlag) { String commandText = "--project=" + sessionContext.getProjectName(); UseProjectCommand useProjectCommand = new UseProjectCommand(sessionContext.getProjectName(), commandText, sessionContext); int index = 0; boolean loginCommandExist = false; for (AbstractCommand command : commandList) { index++; if (command instanceof LoginCommand) { loginCommandExist = true; break; } } if (loginCommandExist) { commandList.add(index, useProjectCommand); } else { commandList.add(0, useProjectCommand); } } // ?use project?priorty // ?? InstancePriorityCommand boolean ipcExist = false; int useCommandIndex = 0; for (int i = 0; i < commandList.size(); i++) { AbstractCommand command = commandList.get(i); if (command instanceof InstancePriorityCommand) { ipcExist = true; } else if (command instanceof UseProjectCommand) { useCommandIndex = i + 1; } } if (!ipcExist) { // ??InstancePriorityCommand?Priority,? InstancePriorityCommand ipc = new InstancePriorityCommand(sessionContext.getPriority(), "--instance_priority", sessionContext); commandList.add(useCommandIndex, ipc); } } private static void addCommand(List<AbstractCommand> commandList, AbstractCommand command, ExecutionContext sessionContext) { if (command != null) { // command.setContext(sessionContext); commandList.add(command); } } static List<PluginPriorityCommand> ecList; public static void printHelpInfo(List<String> keywords) { Map<String, Integer> matched = new HashMap<String, Integer>() { }; List<String> allCommands = new ArrayList<String>(); if (ecList == null) { ecList = PluginUtil.getExtendCommandList(); } for (PluginPriorityCommand command : ecList) { allCommands.add(command.getCommandName()); } for (String commandName : allCommands) { try { Class<?> commandClass = Class.forName(commandName, false, classLoader); Field tags_field = commandClass.getField(HELP_TAGS_FIELD); String[] tags = (String[]) tags_field.get(null); int count = 0; for (String tag : tags) { for (String keyword : keywords) { if (tag.equalsIgnoreCase(keyword)) { count++; break; } } } if (count != 0) { matched.put(commandName, count); } } catch (ClassNotFoundException e) { // Console??AssertionError //throw new AssertionError("Cannot find the command:" + commandName); e.printStackTrace(); } catch (NoSuchFieldException e) { // Ignore } catch (IllegalAccessException e) { // Ignore } } // Print the help info of the command(s) whose tags match most keywords boolean found = false; System.out.println(); for (int i = keywords.size(); i >= 1; i--) { for (Map.Entry<String, Integer> entry : matched.entrySet()) { if (i == entry.getValue()) { try { Class<?> commandClass = Class.forName(entry.getKey(), false, classLoader); Method printMethod = commandClass.getDeclaredMethod(HELP_PRINT_METHOD, new Class<?>[] { PrintStream.class }); printMethod.invoke(null, System.out); found = true; } catch (ClassNotFoundException e) { // Console??AssertionError throw new AssertionError("Cannot find the command:" + entry.getKey()); } catch (NoSuchMethodException e) { // Ignore } catch (IllegalAccessException e) { // Ignore } catch (InvocationTargetException e) { // Ignore } } } if (found) { break; } } System.out.println(); } private static void parseCommandLineCommand(List<AbstractCommand> commandList, List<String> optionList, ExecutionContext sessionContext) throws ODPSConsoleException { for (int i = 0; i < COMMANDLINE_COMMANDS.length; i++) { String commandName = COMMAND_PACKAGE + "." + COMMANDLINE_COMMANDS[i]; AbstractCommand cmd = reflectCommandObject(commandName, new Class<?>[] { List.class, ExecutionContext.class }, optionList, sessionContext); addCommand(commandList, cmd, sessionContext); } if (ecList == null) { ecList = PluginUtil.getExtendCommandList(); } for (PluginPriorityCommand command : ecList) { String commandName = command.getCommandName(); if (commandName != null && !"".equals(commandName.trim())) { AbstractCommand cmd = null; try { cmd = reflectCommandObject(commandName, new Class<?>[] { List.class, ExecutionContext.class }, optionList, sessionContext); } catch (AssertionError e) { // ?,console??? sessionContext.getOutputWriter().writeDebug(e.getMessage()); System.err.println("fail to load user command, pls check:" + commandName); } if (cmd != null) { addCommand(commandList, cmd, sessionContext); return; } } } } private static void parseInteractiveCommand(List<AbstractCommand> commandList, String commandText, ExecutionContext sessionContext, int queryNumber) throws ODPSConsoleException { if (ecList == null) { ecList = PluginUtil.getExtendCommandList(); } for (int i = 0; i < INTERACTIVE_COMMANDS.length; i++) { String commandName = COMMAND_PACKAGE + "." + INTERACTIVE_COMMANDS[i]; // ? ecList.add(new PluginPriorityCommand(commandName, PluginPriorityCommand.MAX_PRIORITY)); } // console? String userCommands = sessionContext.getUserCommands(); if (userCommands != null) { // ???? for (String commandString : Arrays.asList(userCommands.split(","))) { ecList.add(new PluginPriorityCommand(commandString, PluginPriorityCommand.MAX_PRIORITY)); } } // QueryCommand, ecList.add(new PluginPriorityCommand(COMMAND_PACKAGE + "." + "QueryCommand", PluginPriorityCommand.MIN_PRIORITY)); Collections.sort(ecList); for (PluginPriorityCommand command : ecList) { String commandName = command.getCommandName(); if (commandName != null && !"".equals(commandName.trim())) { AbstractCommand cmd = null; try { cmd = reflectCommandObject(commandName, new Class<?>[] { String.class, ExecutionContext.class }, commandText, sessionContext); } catch (AssertionError e) { // ?,console??? sessionContext.getOutputWriter().writeDebug(e.getMessage()); System.err.println("fail to load user command, pls check:" + commandName); } if (cmd != null) { cmd.setCommandStep(queryNumber); addCommand(commandList, cmd, sessionContext); return; } } } } static URLClassLoader classLoader; public static void loadPlugins() { List<URL> pluginJarList = PluginUtil.getPluginsJarList(); URL[] urls = (URL[]) pluginJarList.toArray(new URL[pluginJarList.size()]); classLoader = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader()); } private static AbstractCommand reflectCommandObject(String commandName, Class<?>[] argTypes, Object... args) throws ODPSConsoleException { Class<?> commandClass = null; try { if (classLoader == null) { loadPlugins(); } commandClass = Class.forName(commandName, false, classLoader); Method parseMethod = commandClass.getDeclaredMethod("parse", argTypes); Object commandObject = parseMethod.invoke(null, args); if (commandObject != null) { return (AbstractCommand) commandObject; } else { return null; } } catch (ClassNotFoundException e) { // Console??AssertionError throw new AssertionError("Cannot find the command:" + commandName); } catch (SecurityException e) { throw new AssertionError("Cannot find the parse method on the command: " + commandName); } catch (NoSuchMethodException e) { //FOR there's two kind of command,not throw exception return null; } catch (IllegalArgumentException e) { throw new AssertionError("Failed to invoke the parse method on the command:" + commandName); } catch (IllegalAccessException e) { throw new AssertionError("Failed to invoke the parse method on the command:" + commandName); } catch (InvocationTargetException e) { if (e.getCause() instanceof ODPSConsoleException) { String msg = e.getCause().getMessage(); if (!StringUtils.isNullOrEmpty(msg) && msg.contains(ODPSConsoleConstants.BAD_COMMAND) && commandClass != null) { String output = getCommandUsageString(commandClass); if (output != null) { throw new ODPSConsoleException(e.getCause().getMessage() + "\n" + output); } } throw (ODPSConsoleException) e.getCause(); } else { throw new ODPSConsoleException(e.getCause()); } } } private static String getCommandUsageString(Class<?> commandClass) { try { ByteArrayOutputStream os = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(os); Method printMethod = commandClass.getDeclaredMethod("printUsage", new Class<?>[] { PrintStream.class }); printMethod.invoke(null, ps); return os.toString("UTF8"); } catch (Exception e) { return null; } } // ??-e"", --project=??option private static List<String> populateOptions(List<String> optionList) { List<String> resultList = new LinkedList<String>(); for (String optionStr : optionList) { if (!StringUtils.isNullOrEmpty(optionStr)) { String option = optionStr.trim(); if (option.matches("^--[^= ]+ *= *[^ ]+")) { // ^--[^-= ]+ *= *[^ ]+ String[] cmds = option.split("=", 2); // ??command? if (cmds[0].trim().equals("--username")) { resultList.add("-u"); } else if (cmds[0].trim().equals("--password")) { resultList.add("-p"); } else { resultList.add(cmds[0].trim()); } resultList.add(cmds[1].trim()); } else if (option.matches("-[a-z].+")) { resultList.add(option.substring(0, 2)); resultList.add(option.substring(2)); } else { resultList.add(option); } } } return resultList; } }