001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2016 005 * Space Science and Engineering Center (SSEC) 006 * University of Wisconsin - Madison 007 * 1225 W. Dayton Street, Madison, WI 53706, USA 008 * https://www.ssec.wisc.edu/mcidas 009 * 010 * All Rights Reserved 011 * 012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 013 * some McIDAS-V source code is based on IDV and VisAD source code. 014 * 015 * McIDAS-V is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU Lesser Public License as published by 017 * the Free Software Foundation; either version 3 of the License, or 018 * (at your option) any later version. 019 * 020 * McIDAS-V is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU Lesser Public License for more details. 024 * 025 * You should have received a copy of the GNU Lesser Public License 026 * along with this program. If not, see http://www.gnu.org/licenses. 027 */ 028package edu.wisc.ssec.mcidasv.startupmanager.options; 029 030import java.awt.event.ItemEvent; 031import java.awt.event.ItemListener; 032 033import javax.swing.JComboBox; 034import javax.swing.SwingUtilities; 035 036import org.slf4j.LoggerFactory; 037 038import ch.qos.logback.classic.Level; 039import ch.qos.logback.classic.Logger; 040 041import edu.wisc.ssec.mcidasv.startupmanager.options.OptionMaster.OptionPlatform; 042import edu.wisc.ssec.mcidasv.startupmanager.options.OptionMaster.Type; 043import edu.wisc.ssec.mcidasv.startupmanager.options.OptionMaster.Visibility; 044import edu.wisc.ssec.mcidasv.util.McVGuiUtils; 045 046/** 047 * Representation of a choice allowing the user to select the global McIDAS-V 048 * logging level. 049 */ 050public class LoggerLevelOption extends AbstractOption { 051 052 /** 053 * {@code String} representation of Logback's {@literal "TRACE"} logging 054 * level. 055 */ 056 private static final String TRACE = Level.TRACE.toString(); 057 058 /** 059 * {@code String} representation of Logback's {@literal "DEBUG"} logging 060 * level. 061 */ 062 private static final String DEBUG = Level.DEBUG.toString(); 063 064 /** 065 * {@code String} representation of Logback's {@literal "INFO"} logging 066 * level. 067 */ 068 private static final String INFO = Level.INFO.toString(); 069 070 /** 071 * {@code String} representation of Logback's {@literal "WARN"} logging 072 * level. 073 */ 074 private static final String WARN = Level.WARN.toString(); 075 076 /** 077 * {@code String} representation of Logback's {@literal "ERROR"} logging 078 * level. 079 */ 080 private static final String ERROR = Level.ERROR.toString(); 081 082 /** 083 * {@code String} representation of Logback's {@literal "OFF"} logging 084 * level. 085 */ 086 private static final String OFF = Level.OFF.toString(); 087 088 /** 089 * {@code JComboBox} that will eventually contain logging levels to 090 * select. May be {@code null}. 091 */ 092 private JComboBox<String> comboBox; 093 094 /** 095 * {@code String} representation of the user's selection, or the default 096 * value provided to the constructor. 097 */ 098 private String currentChoice; 099 100 /** 101 * Create a startup option that allows the user to manipulate the global 102 * McIDAS-V logging level. <B>NOTE:</b> {@code null} is not a permitted 103 * value for any of this constructor's parameters. 104 * 105 * @param id Identifier for this startup option. 106 * @param label Brief description suitable for a GUI label. 107 * @param defaultValue Default value for this startup option. 108 * @param optionPlatform Platforms where this option may be applied. 109 * @param optionVisibility Whether or not the option is presented via the GUI. 110 * 111 * @throws IllegalArgumentException if {@code defaultValue} failed {@link #isValidValue(String)}. 112 */ 113 public LoggerLevelOption(String id, String label, String defaultValue, 114 OptionPlatform optionPlatform, Visibility optionVisibility) { 115 super(id, label, Type.LOGLEVEL, optionPlatform, optionVisibility); 116 if (!isValidValue(defaultValue)) { 117 throw new IllegalArgumentException("Default value '"+defaultValue+"' is not one of: TRACE, DEBUG, INFO, WARN, ERROR, or OFF."); 118 } 119 currentChoice = defaultValue; 120 } 121 122 /** 123 * Builds a {@link JComboBox} containing the logging levels to select. 124 * Defaults to the {@code String} specified in the constructor. 125 * 126 * @return {@code JComboBox} to present to the user. 127 */ 128 @Override public JComboBox<String> getComponent() { 129 comboBox = new JComboBox<>(new String[] { TRACE, DEBUG, INFO, WARN, ERROR, OFF }); 130 comboBox.setSelectedItem(currentChoice); 131 comboBox.addItemListener(e -> setValue(comboBox.getSelectedItem().toString())); 132 133 McVGuiUtils.setComponentWidth(comboBox, McVGuiUtils.Width.ONEHALF); 134 return comboBox; 135 } 136 137 /** 138 * Returns the user's current selection (or the default value). 139 * 140 * @return Current selection or default value. 141 */ 142 @Override public String getValue() { 143 return currentChoice; 144 } 145 146 /** 147 * Stores the user's selected logging level. Note that this can be called 148 * from third-party or the GUI! If the call originates from the GUI, an 149 * infinite loop is avoided by using the {@link JComboBox#setSelectedItem(Object)} 150 * behavior that does <b>not</b> generate {@link ItemEvent ItemEvents} if 151 * the selection did not actually change. 152 * 153 * @param value {@code String} representation of the desired logging 154 * level. Should not be {@code null}. 155 * 156 * @throws IllegalArgumentException if {@code value} failed 157 * {@link #isValidValue(String)}. 158 */ 159 @Override public void setValue(String value) { 160 if (!isValidValue(value)) { 161 throw new IllegalArgumentException("Value '"+value+"' is not one of: TRACE, DEBUG, INFO, WARN, ERROR, or OFF."); 162 } 163 currentChoice = value; 164 Logger rootLogger = (Logger)LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); 165 rootLogger.setLevel(stringToLogback(value)); 166 SwingUtilities.invokeLater(() -> { 167 if (comboBox != null) { 168 comboBox.setSelectedItem(currentChoice); 169 } 170 }); 171 } 172 173 /** 174 * Converts a {@code String} value to the corresponding logging level. 175 * 176 * <p>This functionality is similar to 177 * {@link Level#toLevel(String, Level)}, but for this use case it is 178 * preferable to know if an invalid {@code value} was provided.</p> 179 * 180 * @param value Value to convert. 181 * 182 * @return Logging level. 183 * 184 * @throws IllegalArgumentException if {@code value} did not have a 185 * corresponding logging level. 186 */ 187 private static Level stringToLogback(final String value) { 188 Level level; 189 if (TRACE.equalsIgnoreCase(value)) { 190 level = Level.TRACE; 191 } else if (DEBUG.equalsIgnoreCase(value)) { 192 level = Level.DEBUG; 193 } else if (INFO.equalsIgnoreCase(value)) { 194 level = Level.INFO; 195 } else if (WARN.equalsIgnoreCase(value)) { 196 level = Level.WARN; 197 } else if (ERROR.equalsIgnoreCase(value)) { 198 level = Level.ERROR; 199 } else if (OFF.equalsIgnoreCase(value)) { 200 level = Level.OFF; 201 } else { 202 throw new IllegalArgumentException(); 203 } 204 return level; 205 } 206 207 /** 208 * Tests a {@code String} value to see if it has a corresponding logging 209 * level. 210 * 211 * @param value Value to test. 212 * 213 * @return {@code true} if-and-only-if passes a 214 * {@link String#equalsIgnoreCase(String)} check against {@link #TRACE}, 215 * {@link #DEBUG}, {@link #INFO}, {@link #WARN}, {@link #ERROR}, or 216 * {@link #OFF}. 217 */ 218 private static boolean isValidValue(final String value) { 219 return (TRACE.equalsIgnoreCase(value) || 220 DEBUG.equalsIgnoreCase(value) || 221 INFO.equalsIgnoreCase(value) || 222 WARN.equalsIgnoreCase(value) || 223 ERROR.equalsIgnoreCase(value) || 224 OFF.equalsIgnoreCase(value)); 225 } 226 227 /** 228 * {@code String} representation of the user's logging level selection. 229 * 230 * @return {@code String} that looks something like 231 * {@literal "[LoggerLevel@7825114a: currentChoice=INFO]"}. 232 */ 233 public String toString() { 234 return String.format("[LoggerLevelOption@%x: currentChoice=%s]", 235 hashCode(), currentChoice); 236 } 237}