/******************************************************************************* * Copyright 2015-2016 - CNRS (Centre National de Recherche Scientifique) * * 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. * *******************************************************************************/ /* * 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 2, 2015nership. 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 eu.project.ttc.tools.cli; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.util.LinkedList; import java.util.List; import java.util.Properties; import org.apache.commons.cli.CommandLine; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableList; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.encoder.PatternLayoutEncoder; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.FileAppender; /** * This class consists of static methods used by the CLI. * * @author Sebastián Peña Saldarriaga */ public final class TermSuiteCLIUtils { private static final Logger LOGGER = LoggerFactory.getLogger(TermSuiteCLIUtils.class); /** Name of the parameter that must be set to the input directory */ public static final String P_INPUT_DIR = "directory"; /** Name of the parameter that must be set to the input files' encoding */ public static final String P_ENCODING = "encoding"; /** Name of the parameter that must be set to the input files' language */ public static final String P_LANGUAGE = "language"; /** Name of the parameter that must be set to the configuration file */ public static final String P_PROPERTIES_FILE = "configFile"; /* The corpus format: txt or tei */ public static final String CORPUS_FORMAT = "corpus-format"; /* Possible values for argument corpus-format */ public static final String CORPUS_FORMAT_TXT = "txt"; public static final String CORPUS_FORMAT_TEI = "tei"; /** * Instances should NOT be constructed in standard programming. */ private TermSuiteCLIUtils() {} /** * Unconditionally close an <code>InputStream</code>. Equivalent to * {@link InputStream#close()}, except any exceptions will be ignored. * <p> * Code from apache IOUtils. * * @param input * A (possibly null) InputStream */ public static void closeQuietly(InputStream input) { if (input == null) { return; } try { input.close(); } catch (IOException ioe) { } } /** * Unconditionally close an <code>OutputStream</code>. Equivalent to * {@link OutputStream#close()}, except any exceptions will be ignored. * <p> * Code from apache IOUtils. * * @param output * A (possibly null) OutputStream */ public static void closeQuietly(OutputStream output) { if (output == null) { return; } try { output.close(); } catch (IOException ioe) { } } /** * Reads a list of {@link Properties} from the specified * <code>fileName</code> in the user preferences folder. * * @param fileName * The name of the file to read * @return The properties read, or <code>null</code> if the file cannot be * read. */ @SuppressWarnings("resource") public static Properties readPropertiesFileName(String fileName) { File preFile = new File(fileName); FileInputStream input = null; try { input = new FileInputStream(preFile); Properties props = new Properties(); props.load(input); return props; } catch (IOException e) { return null; } finally { closeQuietly(input); } } /** * Creates a mandatory {@link Option} using the specified arguments. * * @param opt * The name of the option * @param longOpt * The long representation of the option * @param hasArg * Specifies whether the Option takes an argument or not * @param description * Describes the function of the option * @param isMandatory * whether the Option is mandatory * @return The option instance */ public static Option createOption(String opt, String longOpt, boolean hasArg, String description, boolean isMandatory) { Option option = new Option(opt, longOpt, hasArg, description); option.setRequired(isMandatory); return option; } /** * Returns the key of the given option * * @param opt * The option * @return {@link Option#getOpt()} if the value returned is not empty, or * {@link Option#getLongOpt()} otherwise. */ public static String getOptionKey(Option opt) { String key = opt.getOpt(); if (key == null || key.isEmpty()) key = opt.getLongOpt(); return key; } /** * Sets the <code>value</code> of the specified <code>property</code> if no * value exists for it in the given <code>properties</code>. * * @param properties * The property list * @param property * The property name * @param value * The value to set */ public static void setToValueIfNotExists(Properties properties, String property, String value) { if (properties.getProperty(property) == null) properties.setProperty(property, value); } /** * Determines whether the specified <code>property</code> value is * <code>null</code>. * * @param properties * The property list * @param property * The property name * @return <code>true</code> if the value of <code>property</code> is * <code>null</code>, or <code>false</code> otherwise. */ public static boolean isNull(Properties properties, String property) { return properties.getProperty(property) == null; } /** * Reads a file path from a command line option if set and * return the absolute file path as an optional, or exits with a log message if * the file does not exist. * @param line the command line * @param optionName the name of the file path option * @return the string optional set with absolute file path if the option is set. */ public static Optional<String> readFileOption(CommandLine line, String optionName) { if(line.getOptionValue(optionName) != null) { if(!new File(line.getOptionValue(optionName)).exists()) exitWithErrorMessage("File does not exist: " + line.getOptionValue(optionName)); else return Optional.of("file:" + new File(line.getOptionValue(optionName)).getAbsolutePath()); } return Optional.absent(); } private static String in = null; /** * Read the standard input as a string. * @return * @throws IOException */ public static String readIn(String encoding) throws IOException { if(in == null) { InputStreamReader reader = new InputStreamReader(System.in, encoding); List<Character> chars = new LinkedList<Character>(); int c; while(reader.ready() && ((c = reader.read())!= -1)) chars.add((char)c); char[] charAry = new char[chars.size()]; for(int i=0; i<chars.size(); i++) charAry[i] = chars.get(i); in = new String(charAry); } return in; } /** * Prints an error message to the log and exits. * @param aMessage */ public static void exitWithErrorMessage(String aMessage) { LOGGER.error(aMessage); System.err.println(aMessage); System.exit(1); } /** * Prints the command line usage to the std error output * * @param e * The error that raised the help message * @param cmdLine * The command line usage * @param options * The options expected */ public static void printUsage(ParseException e, String cmdLine, Options options) { System.err.println(e.getMessage()); // automatically generate the help statement HelpFormatter formatter = new HelpFormatter(); PrintWriter pw = new PrintWriter(System.err); formatter.printUsage(pw, cmdLine.length() + 7, cmdLine, options); pw.flush(); } /** * Displays all command line options in log messages. * @param line */ public static void logCommandLineOptions(CommandLine line) { for (Option myOption : line.getOptions()) { String message; String opt = ""; if(myOption.getOpt() != null) { opt+="-"+myOption.getOpt(); if(myOption.getLongOpt() != null) opt+=" (--"+myOption.getLongOpt()+")"; } else opt+="--"+myOption.getLongOpt()+""; if(myOption.hasArg()) message = opt + " " + myOption.getValue(); else message = opt; LOGGER.info("with option: " + message); } } private static Stopwatch stopwatch; public static Stopwatch startChrono() { stopwatch = Stopwatch.createStarted(); return stopwatch; } public static void stopChrono() { stopwatch.stop(); LOGGER.info("CLI stopped after " + stopwatch.toString()); } public static void logToFile(String path) { PatternLayoutEncoder ple = new PatternLayoutEncoder(); ple.setPattern("%date %level [%thread] %logger{10} [%file:%line] %msg%n"); ple.setContext((LoggerContext) LoggerFactory.getILoggerFactory()); ple.start(); FileAppender<ILoggingEvent> fa = new FileAppender<ILoggingEvent>(); fa.setName("FileLogger"); fa.setFile(path); fa.setContext((LoggerContext) LoggerFactory.getILoggerFactory()); fa.setEncoder(ple); // fa.setThreshold(ch.qos.logback.classic.Level.DEBUG); fa.setAppend(true); fa.start(); // add appender to any Logger (here is root) ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); rootLogger.addAppender(fa); } public static void disableLogging() { LoggerContext loggerContext = (LoggerContext)LoggerFactory.getILoggerFactory(); loggerContext.stop(); } public static void setGlobalLogLevel(String levelString) { setGlobalLogLevel(getLevel(levelString)); } public static void setGlobalLogLevel(Level level) { ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); logger.setLevel(level); } public static void setLogLevel(Object... loggerOverridings) { Preconditions.checkArgument(loggerOverridings.length%2==0); for(int i=0; i<loggerOverridings.length; i+=2) { Class<?> cls = (Class<?>)loggerOverridings[i]; Level level = getLevel((String)loggerOverridings[i+1]); LOGGER.debug("Setting log level {} for class {}", level, cls); ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger(cls); logger.setLevel(level); } } public static Level getLevel(String logLevelString) { for(Level level:ImmutableList.of(Level.ALL, Level.ERROR, Level.WARN, Level.INFO, Level.DEBUG, Level.TRACE)) { if(level.toString().toLowerCase().equals(logLevelString.toLowerCase())) return level; } throw new IllegalArgumentException("Invalid log level: " + logLevelString); } }