From 3de8bf931e7b9e2a71a8959a7dd1260d33dc9034 Mon Sep 17 00:00:00 2001 From: Ben Soares Date: Thu, 23 Feb 2023 16:21:19 +0000 Subject: [PATCH] JAL-629 bootstrap args and properties. Remember index of args for 'previous structure' defaulting of other args --- src/jalview/bin/ArgParser.java | 212 +++++++++++++++++++++++++++++++--------- src/jalview/bin/Cache.java | 65 +++++++++++- src/jalview/bin/Commands.java | 76 +++++++------- src/jalview/bin/Console.java | 28 +++++- src/jalview/bin/Jalview.java | 75 +++++++------- src/jalview/log/JLogger.java | 10 ++ 6 files changed, 347 insertions(+), 119 deletions(-) diff --git a/src/jalview/bin/ArgParser.java b/src/jalview/bin/ArgParser.java index 338d130..d150db2 100644 --- a/src/jalview/bin/ArgParser.java +++ b/src/jalview/bin/ArgParser.java @@ -23,6 +23,7 @@ package jalview.bin; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.Enumeration; @@ -59,7 +60,7 @@ public class ArgParser USAGESTATS, OPEN, OPEN2, PROPS, QUESTIONNAIRE, SETPROP, TREE, VDOC, VSESS, OUTPUT, OUTPUTTYPE, SSANNOTATION, NOTEMPFAC, TEMPFAC, TEMPFAC_LABEL, TEMPFAC_DESC, TEMPFAC_SHADING, TITLE, PAEMATRIX, WRAP, - NOSTRUCTURE, STRUCTURE, IMAGE, QUIT; + NOSTRUCTURE, STRUCTURE, IMAGE, QUIT, DEBUG("d"); static { @@ -111,6 +112,7 @@ public class ArgParser WRAP.setOptions(Opt.BOOLEAN, Opt.LINKED); IMAGE.setOptions(Opt.STRING, Opt.LINKED); QUIT.setOptions(Opt.UNARY); + DEBUG.setOptions(Opt.BOOLEAN); } private final String[] argNames; @@ -119,6 +121,8 @@ public class ArgParser private boolean defaultBoolValue = false; + private int argIndex = -1; + public String toLongString() { StringBuilder sb = new StringBuilder(); @@ -201,6 +205,16 @@ public class ArgParser { return defaultBoolValue; } + + private void setArgIndex(int i) + { + this.argIndex = i; + } + + protected int getArgIndex() + { + return this.argIndex; + } } public static class ArgValues @@ -213,12 +227,16 @@ public class ArgParser private boolean negated = false; - private List argsList; + private int singleArgIndex = -1; + + private List argsIndexes; + + private List argsList; protected ArgValues(Arg a) { this.arg = a; - this.argsList = new ArrayList(); + this.argsList = new ArrayList(); this.boolValue = arg.getDefaultBoolValue(); } @@ -272,8 +290,9 @@ public class ArgParser { sb.append("Values:"); boolean first = true; - for (String v : argsList) + for (ArgValue av : argsList) { + String v = av.getValue(); if (!first) sb.append(","); sb.append("\n '"); @@ -288,25 +307,24 @@ public class ArgParser protected void addValue() { - addValue(null); + addValue(null, -1); } - protected void addValue(String val) + protected void addValue(String val, int argIndex) { - addValue(val, false); + addValue(val, argIndex, false); } - protected void addValue(String val, boolean noDuplicates) + protected void addValue(String val, int argIndex, boolean noDuplicates) { if ((!arg.hasOption(Opt.MULTI) && argsList.size() > 0) || (noDuplicates && argsList.contains(val))) return; if (argsList == null) { - Console.warn("** inst"); - argsList = new ArrayList(); + argsList = new ArrayList(); } - argsList.add(val); + argsList.add(new ArgValue(val, argIndex)); } protected boolean hasValue(String val) @@ -314,14 +332,22 @@ public class ArgParser return argsList.contains(val); } - protected String getValue() + protected ArgValue getArgValue() { if (arg.hasOption(Opt.MULTI)) Console.warn("Requesting single value for multi value argument"); return argsList.size() > 0 ? argsList.get(0) : null; } - protected List getValues() + /* + protected String getValue() + { + ArgValue av = getArgValue(); + return av == null ? null : av.getValue(); + } + */ + + protected List getArgValueList() { return argsList; } @@ -454,6 +480,7 @@ public class ArgParser // new style Enumeration argE = Collections.enumeration(Arrays.asList(args)); + int argIndex = 0; while (argE.hasMoreElements()) { String arg = argE.nextElement(); @@ -555,7 +582,7 @@ public class ArgParser // store appropriate value if (a.hasOption(Opt.STRING)) { - values.addValue(val); + values.addValue(val, argIndex); } else if (a.hasOption(Opt.BOOLEAN)) { @@ -675,23 +702,29 @@ public class ArgParser return m == null ? null : m.get(a); } - public static List getValues(Map m, Arg a) + public static List getArgValueList(Map m, Arg a) { ArgValues av = getArgValues(m, a); - return av == null ? null : av.getValues(); + return av == null ? null : av.getArgValueList(); } - public static String getValue(Map m, Arg a) + public static ArgValue getArgValue(Map m, Arg a) { - List vals = getValues(m, a); + List vals = getArgValueList(m, a); return (vals == null || vals.size() == 0) ? null : vals.get(0); } + public static String getValue(Map m, Arg a) + { + ArgValue av = getArgValue(m, a); + return av == null ? null : av.getValue(); + } + public static boolean hasValue(Map m, Arg a) { if (!m.containsKey(a)) return false; - return getValue(m, a) != null; + return getArgValue(m, a) != null; } public static boolean getBoolean(Map m, Arg a) @@ -700,9 +733,35 @@ public class ArgParser return av == null ? false : av.getBoolean(); } - public static SubVal getSubVal(String item) + public static SubVals getSubVals(String item) { - return new SubVal(item); + return new SubVals(item); + } + + /** + * A helper class to keep an index of argument position with argument values + */ + public static class ArgValue + { + private int argIndex; + + private String value; + + protected ArgValue(String value, int argIndex) + { + this.value = value; + this.argIndex = argIndex; + } + + protected String getValue() + { + return value; + } + + protected int getArgIndex() + { + return argIndex; + } } /** @@ -711,50 +770,60 @@ public class ArgParser * the strings keyName and keyValue, and the content after the square brackets * (if present). Values not set `will be -1 or null. */ - public static class SubVal + public static class SubVals { private static int NOTSET = -1; - protected int index = NOTSET; + private int index = NOTSET; - protected String keyName = null; + private Map subVals = null; - protected String keyValue = null; + private static char SEPARATOR = ';'; - protected String content = null; + private String content = null; - public SubVal(String item) + public SubVals(String item) { - this.parseVal(item); + this.parseVals(item); } - public void parseVal(String item) + public void parseVals(String item) { if (item.indexOf('[') == 0 && item.indexOf(']') > 1) { int openBracket = item.indexOf('['); int closeBracket = item.indexOf(']'); - String indexString = item.substring(openBracket + 1, closeBracket); + String subvalsString = item.substring(openBracket + 1, + closeBracket); this.content = item.substring(closeBracket + 1); - int equals = indexString.indexOf('='); - if (equals > -1) + boolean setIndex = false; + for (String subvalString : subvalsString + .split(Character.toString(SEPARATOR))) { - this.keyName = indexString.substring(0, equals); - this.keyValue = indexString.substring(equals + 1); - this.index = -1; - } - else - { - try + int equals = subvalString.indexOf('='); + if (equals > -1) { - this.index = Integer.parseInt(indexString); - } catch (NumberFormatException e) + if (subVals == null) + subVals = new HashMap<>(); + subVals.put(subvalString.substring(0, equals), + subvalString.substring(equals + 1)); + } + else { - Console.warn("Failed to obtain subvalue or index from '" + item - + "'. Setting index=0 and using content='" + content - + "'."); + try + { + this.index = Integer.parseInt(subvalString); + setIndex = true; + } catch (NumberFormatException e) + { + Console.warn("Failed to obtain subvalue or index from '" + + item + "'. Setting index=0 and using content='" + + content + "'."); + } } } + if (!setIndex) + this.index = NOTSET; } else { @@ -765,7 +834,60 @@ public class ArgParser public boolean notSet() { // notSet is true if content present but nonsensical - return index == NOTSET && keyName == null && keyValue == null; + return index == NOTSET && subVals == null; + } + + public String get(String key) + { + return subVals == null ? null : subVals.get(key); + } + + public boolean has(String key) + { + return subVals == null ? false : subVals.containsKey(key); + } + + public int getIndex() + { + return index; + } + + public String getContent() + { + return content; + } + } + + private static final Collection bootstrapArgs = new ArrayList( + Arrays.asList("props", "debug")); + + public static Map bootstrapArgs(String[] args) + { + Map argMap = new HashMap<>(); + if (args == null) + return argMap; + Enumeration argE = Collections.enumeration(Arrays.asList(args)); + while (argE.hasMoreElements()) + { + String arg = argE.nextElement(); + String argName = null; + String val = null; + if (arg.startsWith("--")) + { + int equalPos = arg.indexOf('='); + if (equalPos > -1) + { + argName = arg.substring(2, equalPos); + val = arg.substring(equalPos + 1); + } + else + { + argName = arg.substring(2); + } + if (bootstrapArgs.contains(argName)) + argMap.put(argName, val); + } } + return argMap; } } \ No newline at end of file diff --git a/src/jalview/bin/Cache.java b/src/jalview/bin/Cache.java index a75a27f..698cbb8 100755 --- a/src/jalview/bin/Cache.java +++ b/src/jalview/bin/Cache.java @@ -24,7 +24,9 @@ import java.awt.Color; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; @@ -34,7 +36,9 @@ import java.net.PasswordAuthentication; import java.net.URL; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Enumeration; @@ -320,6 +324,8 @@ public class Cache /** Default file is ~/.jalview_properties */ static String propertiesFile; + private static final String fallbackPropertiesFile = ".jalview_properties"; + private static boolean propsAreReadOnly = Platform.isJS(); public static boolean isPropsAreReadOnly() @@ -347,7 +353,7 @@ public class Cache { String channelPrefsFilename = ChannelProperties .getProperty("preferences.filename"); - String releasePrefsFilename = ".jalview_properties"; + String releasePrefsFilename = fallbackPropertiesFile; propertiesFile = System.getProperty("user.home") + File.separatorChar + channelPrefsFilename; releasePropertiesFile = System.getProperty("user.home") @@ -1614,4 +1620,61 @@ public class Cache String appbase = getGetdownAppbase(); return appbase + "/" + getdownDistDir + "/build_properties"; } + + private static final Collection bootstrapProperties = new ArrayList<>( + Arrays.asList(JALVIEWLOGLEVEL)); + + public static Properties bootstrapProperties(String filename) + { + Properties bootstrapProps = new Properties(); + File file = null; + if (filename != null) + { + file = new File(filename); + } + if (file == null || !file.exists()) + { + String channelPrefsFilename = ChannelProperties + .getProperty("preferences.filename"); + String propertiesFilename = System.getProperty("user.home") + + File.separatorChar + channelPrefsFilename; + file = new File(propertiesFilename); + } + if (file == null || !file.exists()) + { + String releasePrefsFilename = fallbackPropertiesFile; + String releasePropertiesFilename = System.getProperty("user.home") + + File.separatorChar + releasePrefsFilename; + file = new File(releasePropertiesFilename); + } + + if (filename == null || !file.exists()) + { + System.err.println("Could not load bootstrap preferences file '" + + filename + "'"); + return null; + } + + try + { + FileInputStream in = new FileInputStream(file.getAbsoluteFile()); + Properties props = new Properties(); + props.load(in); + for (String prop : bootstrapProperties) + { + if (props.containsKey(prop)) + bootstrapProps.put(prop, props.getProperty(prop)); + } + } catch (FileNotFoundException e) + { + System.err.println("Could not find bootstrap preferences file '" + + file.getAbsolutePath() + "'"); + } catch (IOException e) + { + System.err.println( + "IOException when loading bootstrap preferences file '" + + file.getAbsolutePath() + "'"); + } + return bootstrapProps; + } } diff --git a/src/jalview/bin/Commands.java b/src/jalview/bin/Commands.java index faf2c9c..a0a3e59 100644 --- a/src/jalview/bin/Commands.java +++ b/src/jalview/bin/Commands.java @@ -14,8 +14,9 @@ import java.util.Map; import jalview.analysis.AlignmentUtils; import jalview.api.AlignmentViewPanel; import jalview.bin.ArgParser.Arg; +import jalview.bin.ArgParser.ArgValue; import jalview.bin.ArgParser.ArgValues; -import jalview.bin.ArgParser.SubVal; +import jalview.bin.ArgParser.SubVals; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.SequenceI; @@ -133,8 +134,9 @@ public class Commands boolean first = true; AlignFrame af; - for (String openFile : ArgParser.getValues(m, Arg.OPEN)) + for (ArgValue av : ArgParser.getArgValueList(m, Arg.OPEN)) { + String openFile = av.getValue(); if (openFile == null) continue; @@ -219,8 +221,9 @@ public class Commands { try { - tempfacType = StructureImportSettings.TFType.valueOf(ArgParser - .getValue(m, Arg.TEMPFAC).toUpperCase(Locale.ROOT)); + tempfacType = StructureImportSettings.TFType + .valueOf(ArgParser.getArgValue(m, Arg.TEMPFAC) + .getValue().toUpperCase(Locale.ROOT)); Console.debug("Obtained Temperature Factor type of '" + tempfacType + "'"); } catch (IllegalArgumentException e) @@ -362,9 +365,10 @@ public class Commands AlignFrame af = afMap.get(id); if (ArgParser.getArgValues(m, Arg.STRUCTURE) != null) { - for (String val : ArgParser.getValues(m, Arg.STRUCTURE)) + for (ArgValue av : ArgParser.getArgValueList(m, Arg.STRUCTURE)) { - SubVal subId = new SubVal(val); + String val = av.getValue(); + SubVals subId = new SubVals(val); SequenceI seq = getSpecifiedSequence(af, subId); if (seq == null) { @@ -375,9 +379,10 @@ public class Commands continue; } File structureFile = null; - if (subId.content != null && subId.content.length() != 0) + if (subId.getContent() != null + && subId.getContent().length() != 0) { - structureFile = new File(subId.content); + structureFile = new File(subId.getContent()); Console.debug("Using structure file (from argument) '" + structureFile.getAbsolutePath() + "'"); } @@ -416,15 +421,16 @@ public class Commands } // load a pAE file if given - if (ArgParser.getValues(m, Arg.PAEMATRIX) != null) + if (ArgParser.getArgValueList(m, Arg.PAEMATRIX) != null) { AlignFrame af = afMap.get(id); if (af != null) { - for (String val : ArgParser.getValues(m, Arg.PAEMATRIX)) + for (ArgValue av : ArgParser.getArgValueList(m, Arg.PAEMATRIX)) { - SubVal subVal = ArgParser.getSubVal(val); - File paeFile = new File(subVal.content); + String val = av.getValue(); + SubVals subVals = ArgParser.getSubVals(val); + File paeFile = new File(subVals.getContent()); String paePath = null; try { @@ -435,36 +441,34 @@ public class Commands Console.warn( "Problem with the PAE file path: '" + paePath + "'"); } - String structId = "structid".equals(subVal.keyName) - ? subVal.keyValue - : null; - if (subVal.notSet()) + String structId = subVals.get("structid"); + if (subVals.notSet()) { // take structid from pdbfilename } - if ("structfile".equals(subVal.keyName)) + if (subVals.has("structfile")) { Console.info("***** Attaching paeFile '" + paePath + "' to " - + subVal.keyName + "=" + subVal.keyValue); + + "structfile=" + subVals.get("structfile")); EBIAlfaFold.addAlphaFoldPAEToStructure( af.getCurrentView().getAlignment(), paeFile, - subVal.index, subVal.keyValue, false); + subVals.getIndex(), subVals.get("structfile"), false); } - else if ("structid".equals(subVal.keyName)) + else if (subVals.has("structid")) { Console.info("***** Attaching paeFile '" + paePath + "' to " - + subVal.keyName + "=" + subVal.keyValue); + + "structid=" + subVals.get("structid")); EBIAlfaFold.addAlphaFoldPAEToStructure( af.getCurrentView().getAlignment(), paeFile, - subVal.index, subVal.keyValue, true); + subVals.getIndex(), subVals.get("structid"), true); } else { Console.debug("***** Attaching paeFile '" + paePath - + "' to sequence index " + subVal.index); + + "' to sequence index " + subVals.getIndex()); EBIAlfaFold.addAlphaFoldPAEToSequence( af.getCurrentView().getAlignment(), paeFile, - subVal.index, null); + subVals.getIndex(), null); // required to readjust the height and position of the pAE // annotation } @@ -503,17 +507,18 @@ public class Commands return; } - if (ArgParser.getValues(m, Arg.IMAGE) != null) + if (ArgParser.getArgValueList(m, Arg.IMAGE) != null) { - for (String val : ArgParser.getValues(m, Arg.IMAGE)) + for (ArgValue av : ArgParser.getArgValueList(m, Arg.IMAGE)) { - SubVal subVal = new SubVal(val); + String val = av.getValue(); + SubVals subVal = new SubVals(val); String type = "png"; // default - String fileName = subVal.content; + String fileName = subVal.getContent(); File file = new File(fileName); - if ("type".equals(subVal.keyName)) + if (subVal.has("type")) { - type = subVal.keyValue; + type = subVal.get("type"); } else if (fileName != null) { @@ -552,16 +557,17 @@ public class Commands } } - private SequenceI getSpecifiedSequence(AlignFrame af, SubVal subId) + private SequenceI getSpecifiedSequence(AlignFrame af, SubVals subId) { AlignmentI al = af.getCurrentView().getAlignment(); - if (-1 < subId.index && subId.index < al.getSequences().size()) + if (-1 < subId.getIndex() + && subId.getIndex() < al.getSequences().size()) { - return al.getSequenceAt(subId.index); + return al.getSequenceAt(subId.getIndex()); } - else if ("id".equals(subId.keyName)) + else if (subId.has("seqid")) { - return al.findName(subId.keyValue); + return al.findName(subId.get("seqid")); } return null; } diff --git a/src/jalview/bin/Console.java b/src/jalview/bin/Console.java index b85a4d2..b868e7b 100644 --- a/src/jalview/bin/Console.java +++ b/src/jalview/bin/Console.java @@ -212,29 +212,47 @@ public class Console public static JLogger.LogLevel getCachedLogLevel(String key) { - return JLogger.toLevel(Cache.getDefault(key, "INFO")); + return getLogLevel(Cache.getDefault(key, "INFO")); + } + + public static JLogger.LogLevel getLogLevel(String level) + { + return JLogger.toLevel(level); } public static boolean initLogger() { + return initLogger(null); + } + + public static boolean initLogger(String providedLogLevel) + { if (log != null) { return true; } try { - JLogger.LogLevel cachedLevel = getCachedLogLevel(); + JLogger.LogLevel logLevel = JLogger.LogLevel.INFO; + + if (JLogger.isLevel(providedLogLevel)) + logLevel = Console.getLogLevel(providedLogLevel); + else + logLevel = getCachedLogLevel(); + if (!Platform.isJS()) { - Log4j.init(cachedLevel); + System.err + .println("Setting initial log level to " + logLevel.name()); + Log4j.init(logLevel); } // log output // is laxis used? Does getLogger do anything without a Logger object? // Logger laxis = Log4j.getLogger("org.apache.axis", myLevel); - JLoggerLog4j.getLogger("org.apache.axis", cachedLevel); + JLoggerLog4j.getLogger("org.apache.axis", logLevel); // The main application logger - log = JLoggerLog4j.getLogger(Cache.JALVIEW_LOGGER_NAME, cachedLevel); + log = JLoggerLog4j.getLogger(Cache.JALVIEW_LOGGER_NAME, logLevel); } catch (NoClassDefFoundError e) { System.err.println("Could not initialise the logger framework"); diff --git a/src/jalview/bin/Jalview.java b/src/jalview/bin/Jalview.java index 402235b..71c6cf0 100755 --- a/src/jalview/bin/Jalview.java +++ b/src/jalview/bin/Jalview.java @@ -40,6 +40,7 @@ import java.security.Policy; import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.Properties; import java.util.Vector; import java.util.logging.ConsoleHandler; import java.util.logging.Level; @@ -278,30 +279,11 @@ public class Jalview if (!Platform.isJS()) { System.setSecurityManager(null); - - Runtime.getRuntime().addShutdownHook(new Thread() - { - public void run() - { - Console.debug("Running shutdown hook"); - if (QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT) - { - // Got to here by a SIGTERM signal. - // Note we will not actually cancel the quit from here -- it's too - // late -- but we can wait for saving files. - Console.debug("Checking for saving files"); - QuitHandler.getQuitResponse(false); - } - else - { - Console.debug("Nothing more to do"); - } - Console.debug("Exiting, bye!"); - // shutdownHook cannot be cancelled, JVM will now halt - } - }); } + // get args needed before proper ArgParser + Map bootstrapArgs = ArgParser.bootstrapArgs(args); + System.out .println("Java version: " + System.getProperty("java.version")); System.out.println("Java Home: " + System.getProperty("java.home")); @@ -330,6 +312,10 @@ public class Jalview System.setProperty("flatlaf.uiScale", "1"); } + // get bootstrap properties (mainly for the logger level) + Properties bootstrapProperties = Cache + .bootstrapProperties(bootstrapArgs.get("props")); + // report Jalview version Cache.loadBuildProperties(true); @@ -340,7 +326,12 @@ public class Jalview try { - Console.initLogger(); + String logLevel = bootstrapArgs.containsKey("debug") ? "DEBUG" : null; + if (logLevel == null && !(bootstrapProperties == null)) + { + logLevel = bootstrapProperties.getProperty(Cache.JALVIEWLOGLEVEL); + } + Console.initLogger(logLevel); } catch (NoClassDefFoundError error) { error.printStackTrace(); @@ -349,23 +340,41 @@ public class Jalview System.exit(0); } - String usrPropsFile = aparser.getValue("props"); - Cache.loadProperties(usrPropsFile); // must do this - // before + // register SIGTERM listener + Runtime.getRuntime().addShutdownHook(new Thread() + { + public void run() + { + Console.debug("Running shutdown hook"); + if (QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT) + { + // Got to here by a SIGTERM signal. + // Note we will not actually cancel the quit from here -- it's too + // late -- but we can wait for saving files. + Console.debug("Checking for saving files"); + QuitHandler.getQuitResponse(false); + } + else + { + Console.debug("Nothing more to do"); + } + Console.debug("Exiting, bye!"); + // shutdownHook cannot be cancelled, JVM will now halt + } + }); + + String usrPropsFile = bootstrapArgs.containsKey("props") + ? bootstrapArgs.get("props") + : aparser.getValue("props"); + Cache.loadProperties(usrPropsFile); if (usrPropsFile != null) { System.out.println( "CMD [-props " + usrPropsFile + "] executed successfully!"); } - // set log level from cache properties - Console.setLogLevel(Cache.getDefault(Cache.JALVIEWLOGLEVEL, "INFO")); - // new ArgParser - ArgParser argparser = new ArgParser(args); // do this after - // Console.initLogger, but TODO - // want --props before then - // CATCH22 + ArgParser argparser = new ArgParser(args); if (argparser.isSet(Arg.HEADLESS)) headless = argparser.getBool(Arg.HEADLESS); diff --git a/src/jalview/log/JLogger.java b/src/jalview/log/JLogger.java index f9859f5..714b0de 100644 --- a/src/jalview/log/JLogger.java +++ b/src/jalview/log/JLogger.java @@ -46,6 +46,16 @@ public abstract class JLogger implements JLoggerI protected abstract void loggerLogMessage(LogLevel level, String message, Throwable t); + public static boolean isLevel(String levelString) + { + for (LogLevel l : LogLevel.values()) + { + if (l.name().equals(levelString)) + return true; + } + return false; + } + public static LogLevel toLevel(String levelString) { try -- 1.7.10.2