/* * ALMA - Atacama Large Millimiter Array * (c) European Southern Observatory, 2002 * Copyright by ESO (in the framework of the ALMA collaboration) * and Cosylab 2002, All rights reserved * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ package alma.acs.gui.loglevel.leveldlg; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.border.TitledBorder; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import org.omg.CORBA.SystemException; import com.cosylab.logging.client.EntryTypeIcon; import com.cosylab.logging.engine.log.LogTypeHelper; import com.cosylab.logging.settings.LogTypeRenderer; import alma.ACSErrTypeCommon.wrappers.AcsJCORBAProblemEx; import alma.ACSErrTypeCommon.wrappers.AcsJIllegalArgumentEx; import alma.Logging.LoggerDoesNotExistEx; import alma.Logging.LoggingConfigurableOperations; import alma.Logging.LoggingConfigurablePackage.LogLevels; import alma.acs.gui.loglevel.LogLvlSelNotSupportedException; import alma.acs.logging.level.AcsLogLevelDefinition; /** * The panel to select the log level of the named loggers * * @author acaproni */ public class LogLevelSelectorPanel extends JPanel implements ActionListener { private static final long serialVersionUID = 5291375242590375664L; // The Button to apply the changes private JButton applyBtn = new JButton("Apply"); // The Button to refresh the list private JButton refreshBtn = new JButton("Refresh"); // The LoggingConfigurable private final LoggingConfigurableOperations logConf; // The table of log levels private LogLevelTable table; private LogLevelModel model; private JComboBox allLocalCB; private JComboBox allGlobalCB; private JLabel minLocal; private JLabel minGlobal; public LogTypeRenderer editorLocal; public LogTypeRenderer editorGlobal; private JButton defaultBtn = new JButton("Reset all loggers to use default levels"); private final Logger logger; /** * Constructor * * @param owner The window that owns this dialog (it can be null) * @param configurable The LoggingConfigurable whose log level * the user wants to read or set * @param logger * @param title The name of the configurable to add to the tile * @throws LogLvlSelNotSupportedException If the configurable does not support selection */ //public LogLevelSelectorPanel(LoggingConfigurableOperations configurable, String name) throws LogLvlSelNotSupportedException { public LogLevelSelectorPanel(LoggingConfigurableOperations configurable, String name, Logger logger) throws Exception { if (configurable==null) { throw new IllegalArgumentException("Invalid null LoggingConfigurable in constructor"); } this.logger = logger; // The editor for local and global log levels String[] descs = new String[LogTypeHelper.values().length]; for (int t=0; t<descs.length; t++) { descs[t]=LogTypeHelper.values()[t].logEntryType; } allLocalCB=new JComboBox(descs); allGlobalCB=new JComboBox(descs); editorLocal= new LogTypeRenderer(); editorGlobal= new LogTypeRenderer(); ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent e) { applyBtn.setEnabled(true); } }; allLocalCB.addActionListener(al); allGlobalCB.addActionListener(al); logConf = configurable; setName(name); initialize(); } /** * Init the GUI * * @throws LogLvlSelNotSupportedException If the configurable does not support selection */ //private void initialize(String name) throws LogLvlSelNotSupportedException { private void initialize() throws Exception { BoxLayout layout = new BoxLayout(this,BoxLayout.Y_AXIS); setLayout(layout); JComponent logLevelsPanel = initLogLevelsPanel(); // Add the panel to set all the levels add(initAllLoggersPanel()); // Add the widgets with the log levels at the center add(logLevelsPanel); // Add the panel to show the minimum log levels add(initMimimumLevelsPanel()); // Set tooltip to buttons applyBtn.setToolTipText("Apply the changes"); refreshBtn.setToolTipText("Refresh the list"); // Add the botton at the bottom JPanel btnPnl = new JPanel(new FlowLayout(FlowLayout.CENTER)); btnPnl.add(applyBtn); btnPnl.add(refreshBtn); applyBtn.addActionListener(this); refreshBtn.addActionListener(this); applyBtn.setEnabled(false); add(btnPnl); } /** * Initialize the log level panel (i.e. the table) * * @return The panel with the table of log levels * * @throws LogLvlSelNotSupportedException If the configurable does not support selection */ private JComponent initLogLevelsPanel() throws AcsJCORBAProblemEx { LogLevelHelper[] levels = loggersLbl(); model = new LogLevelModel(levels); model.addTableModelListener(new TableModelListener(){ public void tableChanged(TableModelEvent e) { applyBtn.setEnabled(userChangedLogLevels()); } }); table = new LogLevelTable(model); JScrollPane scrollPane = new JScrollPane(table); return scrollPane; } /** * Gets the loggers and their levels. * <p> * This method makes remote calls and should not be called in the event thread! * * @return * @throws AcsJCORBAProblemEx In case of ORB / network failure or if remote process is unresponsive or unreachable. */ private LogLevelHelper[] loggersLbl() throws AcsJCORBAProblemEx { List<LogLevelHelper> ret = new ArrayList<LogLevelHelper>(); try { // get the logger names final String[] logNames = logConf.get_logger_names(); // get the log levels for each logger for (String logName : logNames) { try { LogLevels logLevels = logConf.get_logLevels(logName); ret.add(new LogLevelHelper(logName, logLevels)); } catch (LoggerDoesNotExistEx ex) { logger.warning("Failed to retrieve log levels info for logger '" + logName + "'. Will skip this logger."); } } return ret.toArray(new LogLevelHelper[0]); } catch (SystemException ex) { AcsJCORBAProblemEx ex2 = new AcsJCORBAProblemEx(ex); ex2.setInfo("Failed to retrieve logger names or levels."); throw ex2; } } /** * Apply the changes to the log levels, if any. * <p> * TODO: This method makes remote calls and should not be called in the event thread. * However this would require more refactoring, because it currently also accesses swing components. * * @throws AcsJCORBAProblemEx In case of ORB / network failure or if remote process is unresponsive or unreachable. */ private void applyChanges() { try { for (LogLevelHelper logLvl : model.getLevels()) { if (logLvl.modified()) { // see reset of modification flag in the changesApplied call below System.out.println("Applying new log levels to " + logLvl.getName() + ": <" + logLvl.isUsingDefault() + ", " + logLvl.getGlobalLevel() + ", " + logLvl.getLocalLevel() + ">"); logConf.set_logLevels(logLvl.getName(), logLvl.getLogLevels()); } } int localIndex = allLocalCB.getSelectedIndex(); LogTypeHelper local = LogTypeHelper.values()[localIndex]; final int localAcs = local.getAcsCoreLevel().value; int globalIndex = allGlobalCB.getSelectedIndex(); LogTypeHelper global = LogTypeHelper.values()[globalIndex]; final int globalAcs = global.getAcsCoreLevel().value; boolean useDefault = logConf.get_default_logLevels().useDefault; LogLevels toset = new LogLevels(useDefault, (short)globalAcs, (short)localAcs); logConf.set_default_logLevels(toset); model.changesApplied(); updateMinLevels(); applyBtn.setEnabled(false); } catch (SystemException ex) { // AcsJCORBAProblemEx ex2 = new AcsJCORBAProblemEx(ex); String msg = "Failed to set log levels for '" + getName() + "' because of Corba errors. Giving up, also for other loggers of the same process."; logger.log(Level.WARNING, msg, ex); JOptionPane.showMessageDialog(null, msg + " \nCheck the logs for details.", "Error", JOptionPane.ERROR_MESSAGE); } catch (Exception ex) { // AcsJUnexpectedExceptionEx ex2 = new AcsJUnexpectedExceptionEx(ex); String msg = "Failed to set log levels for '" + getName() + "'. Giving up, also for other loggers of the same process."; logger.log(Level.WARNING, msg, ex); JOptionPane.showMessageDialog(null, msg + " \nCheck the logs for details.", "Error", JOptionPane.ERROR_MESSAGE); } } /** * Refresh the list, to see changes made by other operators */ public void refresh() { if (userChangedLogLevels()) { if (JOptionPane.showConfirmDialog(null, "Do you really want to discard changes?", "Confirm", JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) { return; } } try { refreshAllLoggersPanel(); applyChanges(); LogLevelHelper[] levels = null; levels = loggersLbl(); model.setLevels(levels); model.fireTableDataChanged(); applyBtn.setEnabled(false); } catch (Exception ex) { String msg = "Failed to read loggers or levels levels for '" + getName() + "'."; logger.log(Level.WARNING, msg, ex); JOptionPane.showMessageDialog(null, msg + " \nCheck the logs for details.", "Error", JOptionPane.ERROR_MESSAGE); } } /** * * @see java.awt.event.ActionListener */ public void actionPerformed(ActionEvent e) { if (e.getSource()==applyBtn) { applyChanges(); } else if (e.getSource()==refreshBtn) { refresh(); } else if (e.getSource()==defaultBtn) { LogLevelModel llm = (LogLevelModel)table.getModel(); llm.setAllToCommonLevels(); } else if (e.getSource()==allLocalCB) { int index = allLocalCB.getSelectedIndex(); LogTypeHelper newLvl = LogTypeHelper.values()[index]; LogLevelModel llm = (LogLevelModel)table.getModel(); llm.setCommonLocalLevel(newLvl); } else if (e.getSource()==allGlobalCB) { int index = allGlobalCB.getSelectedIndex(); LogTypeHelper newLvl = LogTypeHelper.values()[index]; LogLevelModel llm = (LogLevelModel)table.getModel(); llm.setCommonGlobalLevel(newLvl); } else { throw new IllegalStateException("Unknown source of events: "+e.getSource()); } } /** * Check if the user changed one of the logger level * * @return true if the user changed at least one level */ public boolean userChangedLogLevels() { if (model==null) { // The model is null if the table is not shown // because the client does not support // logLevels operations return false; } LogLevelHelper[] newLevels = model.getLevels(); for (LogLevelHelper logLvl: newLevels) { if (logLvl.modified()) { return true; } } return false; } /** * @return the mimimum level */ private LogTypeHelper getMinLocalLevel() { return getMinLogLevel(true); } /** * @return the minimum level */ private LogTypeHelper getMinGlobalLevel() { return getMinLogLevel(false); } /** * Get the minimum log level among the loggers * * @param isLocal true for local log level, false for global log level * @return the minimum level */ private LogTypeHelper getMinLogLevel(boolean isLocal) { LogTypeHelper errret = LogTypeHelper.TRACE; LogLevelHelper[] levels; try { levels = loggersLbl(); } catch (Exception e) { System.err.println("Function not yet implemented by "+getName()); return errret; } // @todo should this be OFF (OFF is kind of special) int minval = LogTypeHelper.EMERGENCY.getAcsCoreLevel().value; for (LogLevelHelper l : levels) { int val = isLocal ? l.getLocalLevel() : l.getGlobalLevel(); if (minval > val) minval = val; } LogTypeHelper logType; try { AcsLogLevelDefinition levelDef = AcsLogLevelDefinition.fromInteger(minval); logType=LogTypeHelper.fromAcsCoreLevel(levelDef); } catch (Exception e) { System.err.println("Error parsing a log type: "+minval); e.printStackTrace(System.err); return errret; } return logType; } /** * Setup the panel with the option for all the named loggers * * @return * @throws AcsJCORBAProblemEx */ private JPanel initAllLoggersPanel() throws AcsJCORBAProblemEx { TitledBorder border = BorderFactory.createTitledBorder("Process wide default log levels"); JPanel mainPnl = new JPanel(); GridBagLayout gl = new GridBagLayout(); GridBagConstraints gc = new GridBagConstraints(); mainPnl.setLayout(gl); mainPnl.setBorder(border); JLabel localLbl = new JLabel("Default local log level"); allLocalCB.setRenderer(editorLocal); JLabel globalLbl = new JLabel("Default remote log level"); allGlobalCB.setRenderer(editorGlobal); gc.insets = new Insets(5, 5, 5, 5); gc.gridx = 0; gc.gridy = 0; gl.setConstraints(localLbl, gc); mainPnl.add(localLbl); gc.gridx++; gl.setConstraints(allLocalCB, gc); mainPnl.add(allLocalCB); gc.gridx++; gl.setConstraints(globalLbl, gc); mainPnl.add(globalLbl); gc.gridx++; gl.setConstraints(allGlobalCB, gc); mainPnl.add(allGlobalCB); gc.gridx = 0; gc.gridy++; gc.gridwidth = GridBagConstraints.REMAINDER; gl.setConstraints(defaultBtn, gc); mainPnl.add(defaultBtn); // Set the listeners defaultBtn.addActionListener(this); allLocalCB.addActionListener(this); allGlobalCB.addActionListener(this); // set initial choices refreshAllLoggersPanel(); return mainPnl; } /** * This method makes remote calls and should not be called in the event thread! * @throws AcsJCORBAProblemEx In case of ORB / network failure or if remote process is unresponsive or unreachable. */ private void refreshAllLoggersPanel() throws AcsJCORBAProblemEx { try { LogLevels defaultLevels = logConf.get_default_logLevels(); int acsLevel = defaultLevels.minLogLevelLocal; try { LogTypeHelper logTypeLocal = LogTypeHelper.fromAcsCoreLevel(AcsLogLevelDefinition.fromInteger(acsLevel)); allLocalCB.setSelectedIndex(logTypeLocal.ordinal()); model.setCommonLocalLevel(logTypeLocal); } catch (AcsJIllegalArgumentEx e) { logger.warning("Unexpected log level " + acsLevel + " obtained as default minLogLevelLocal."); } acsLevel = defaultLevels.minLogLevel; try { LogTypeHelper logTypeGlobal = LogTypeHelper.fromAcsCoreLevel(AcsLogLevelDefinition.fromInteger(acsLevel)); allGlobalCB.setSelectedIndex(logTypeGlobal.ordinal()); model.setCommonGlobalLevel(logTypeGlobal); } catch (AcsJIllegalArgumentEx e) { logger.warning("Unexpected log level " + acsLevel + " obtained as default minLogLevel."); } } catch (SystemException ex) { AcsJCORBAProblemEx ex2 = new AcsJCORBAProblemEx(ex); ex2.setInfo("Failed to retrieve logger names or levels."); throw ex2; } } /** * Setup the panel to show minimum levels * * @return */ private JPanel initMimimumLevelsPanel() { TitledBorder border = BorderFactory.createTitledBorder("Minimum Log Levels"); JPanel mainPnl = new JPanel(); GridBagLayout gl = new GridBagLayout(); GridBagConstraints gc = new GridBagConstraints(); mainPnl.setLayout(gl); mainPnl.setBorder(border); JLabel localLbl = new JLabel("Current minimum local level"); minLocal = new JLabel(""); JLabel globalLbl = new JLabel("Current minimum remote level"); minGlobal = new JLabel(""); gc.insets = new Insets(5, 10, 5, 10); gc.gridx = 0; gc.gridy = 0; gl.setConstraints(localLbl, gc); mainPnl.add(localLbl); gc.gridx++; gc.insets.right *= 2; gl.setConstraints(minLocal, gc); mainPnl.add(minLocal); gc.gridx++; gc.insets.right /= 2; gl.setConstraints(globalLbl, gc); mainPnl.add(globalLbl); gc.gridx++; gl.setConstraints(minGlobal, gc); mainPnl.add(minGlobal); updateMinLevels(); return mainPnl; } /** * Updates the minimum log level panel */ private void updateMinLevels() { LogTypeHelper minLocalLevel = getMinLocalLevel(); minLocal.setIcon(EntryTypeIcon.getIcon(minLocalLevel)); minLocal.setText(minLocalLevel.toString()); minLocal.repaint(); LogTypeHelper minGlobalLevel = getMinGlobalLevel(); minGlobal.setIcon(EntryTypeIcon.getIcon(minGlobalLevel)); minGlobal.setText(minGlobalLevel.toString()); minLocal.repaint(); } }