You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2012/01/22 11:46:11 UTC

svn commit: r1234478 - in /jmeter/trunk: bin/ src/core/org/apache/jmeter/gui/ src/core/org/apache/jmeter/gui/action/ src/core/org/apache/jmeter/gui/util/ src/core/org/apache/jmeter/resources/ src/jorphan/org/apache/jorphan/logging/ xdocs/

Author: pmouawad
Date: Sun Jan 22 10:46:11 2012
New Revision: 1234478

URL: http://svn.apache.org/viewvc?rev=1234478&view=rev
Log:
Bug 41788 - Log viewer (console window) needed as an option

Added:
    jmeter/trunk/src/core/org/apache/jmeter/gui/LoggerPanel.java   (with props)
    jmeter/trunk/src/core/org/apache/jmeter/gui/action/LoggerPannelEnableDisable.java   (with props)
Modified:
    jmeter/trunk/bin/jmeter.properties
    jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java
    jmeter/trunk/src/core/org/apache/jmeter/gui/MainFrame.java
    jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java
    jmeter/trunk/src/core/org/apache/jmeter/gui/util/JMeterMenuBar.java
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
    jmeter/trunk/src/jorphan/org/apache/jorphan/logging/LoggingManager.java
    jmeter/trunk/xdocs/changes.xml

Modified: jmeter/trunk/bin/jmeter.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/jmeter.properties?rev=1234478&r1=1234477&r2=1234478&view=diff
==============================================================================
--- jmeter/trunk/bin/jmeter.properties (original)
+++ jmeter/trunk/bin/jmeter.properties Sun Jan 22 10:46:11 2012
@@ -121,6 +121,13 @@ jmeter.laf.mac=System
 # See https://issues.apache.org/bugzilla/show_bug.cgi?id=52026 for details
 # N.B. the laf can be defined in user.properties.
 
+# LoggerPanel display
+# default to false
+jmeter.loggerpanel.display=true
+# Max characters kept in LoggerPanel, default to 80000 chars
+# O means no limit
+jmeter.loggerpanel.maxlength=5000
+
 # Toolbar display
 # default:
 #jmeter.toolbar.display=true

Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java?rev=1234478&r1=1234477&r2=1234478&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java Sun Jan 22 10:46:11 2012
@@ -110,6 +110,17 @@ public final class GuiPackage implements
 
     /** The menu item toolbar. */
     private JCheckBoxMenuItem menuToolBar;
+
+    /**
+     * The LoggerPanel menu item
+     */
+    private JCheckBoxMenuItem menuItemLoggerPanel;
+
+    /**
+     * Logger Panel reference
+     */
+    private LoggerPanel loggerPanel;
+
     
     /**
      * Private constructor to permit instantiation only from within this class.
@@ -729,4 +740,35 @@ public final class GuiPackage implements
         list.addAll(stoppables);
         return list;
     }
+
+    /**
+     * Set the menu item LoggerPanel.
+     * @param menuItemLoggerPanel
+     */
+    public void setMenuItemLoggerPanel(JCheckBoxMenuItem menuItemLoggerPanel) {
+        this.menuItemLoggerPanel = menuItemLoggerPanel;
+    }
+    
+    /**
+     * Get the menu item LoggerPanel.
+     *
+     * @return the menu item LoggerPanel
+     */
+    public JCheckBoxMenuItem getMenuItemLoggerPanel() {
+        return menuItemLoggerPanel;
+    }
+
+    /**
+     * @param loggerPanel LoggerPanel
+     */
+    public void setLoggerPanel(LoggerPanel loggerPanel) {
+        this.loggerPanel = loggerPanel;
+    }
+
+    /**
+     * @return the loggerPanel
+     */
+    public LoggerPanel getLoggerPanel() {
+        return loggerPanel;
+    }
 }
\ No newline at end of file

Added: jmeter/trunk/src/core/org/apache/jmeter/gui/LoggerPanel.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/LoggerPanel.java?rev=1234478&view=auto
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/LoggerPanel.java (added)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/LoggerPanel.java Sun Jan 22 10:46:11 2012
@@ -0,0 +1,109 @@
+/*
+ * 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 org.apache.jmeter.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+
+import javax.swing.Box;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+import javax.swing.border.Border;
+import javax.swing.border.EmptyBorder;
+
+import org.apache.jmeter.util.JMeterUtils;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.LogEvent;
+import org.apache.log.LogTarget;
+import org.apache.log.format.PatternFormatter;
+
+/**
+ * Panel that shows log events
+ */
+public class LoggerPanel extends JPanel implements LogTarget {
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 6911128494402594429L;
+    private JTextArea textArea;
+    private PatternFormatter format;
+
+    // Limit length of log content
+    private static final int LOGGER_PANEL_MAX_LENGTH =
+            JMeterUtils.getPropDefault("jmeter.loggerpanel.maxlength", 80000); // $NON-NLS-1$
+
+    /**
+     * 
+     */
+    public LoggerPanel() {
+        init();
+        format = new PatternFormatter(LoggingManager.DEFAULT_PATTERN + "\n");
+    }
+
+    private void init() {
+        this.setLayout(new BorderLayout());
+
+        // MAIN PANEL
+        Border margin = new EmptyBorder(5, 5, 5, 5);
+
+        this.setBorder(margin);
+        
+        // TEXTAREA
+        textArea = new JTextArea();
+        textArea.setEditable(false);
+        textArea.setLineWrap(false);
+        JScrollPane areaScrollPane = new JScrollPane(textArea);
+
+        areaScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+        areaScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+
+        Box mainPanel = Box.createVerticalBox();
+        
+        areaScrollPane.setPreferredSize(new Dimension(mainPanel.getWidth(),mainPanel.getHeight()));
+        mainPanel.add(areaScrollPane);
+        this.add(mainPanel, BorderLayout.CENTER); 
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.log.LogTarget#processEvent(org.apache.log.LogEvent)
+     */
+    public void processEvent(final LogEvent logEvent) {
+        if(!GuiPackage.getInstance().getMenuItemLoggerPanel().getModel().isSelected()) {
+            return;
+        }
+        
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+                synchronized (textArea) {
+                    textArea.append(format.format(logEvent));
+                    int currentLength = textArea.getText().length();
+                    // If LOGGER_PANEL_MAX_LENGTH is 0, it means all log events are kept
+                    if(LOGGER_PANEL_MAX_LENGTH != 0 && currentLength> LOGGER_PANEL_MAX_LENGTH) {
+                        textArea.setText(textArea.getText().substring(Math.max(0, currentLength-LOGGER_PANEL_MAX_LENGTH), 
+                                currentLength));
+                    }
+                    textArea.setCaretPosition(textArea.getText().length());
+                }
+            }
+        });
+    }
+}
\ No newline at end of file

Propchange: jmeter/trunk/src/core/org/apache/jmeter/gui/LoggerPanel.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/MainFrame.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/MainFrame.java?rev=1234478&r1=1234477&r2=1234478&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/MainFrame.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/MainFrame.java Sun Jan 22 10:46:11 2012
@@ -104,6 +104,10 @@ public class MainFrame extends JFrame im
     private static final boolean DISPLAY_TOOLBAR =
             JMeterUtils.getPropDefault("jmeter.toolbar.display", true); // $NON-NLS-1$
 
+    // Allow display/hide LoggerPanel
+    private static final boolean DISPLAY_LOGGER_PANEL =
+            JMeterUtils.getPropDefault("jmeter.loggerpanel.display", false); // $NON-NLS-1$
+
     private static final Logger log = LoggingManager.getLoggerForClass();
 
     /** The menu bar. */
@@ -115,6 +119,9 @@ public class MainFrame extends JFrame im
     /** The panel where the test tree is shown. */
     private JScrollPane treePanel;
 
+    /** The LOG panel. */
+    private LoggerPanel logPanel;
+
     /** The test tree. */
     private JTree tree;
 
@@ -407,8 +414,20 @@ public class MainFrame extends JFrame im
         treePanel = createTreePanel();
         treeAndMain.setLeftComponent(treePanel);
 
+        JSplitPane topAndDown = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+        topAndDown.setOneTouchExpandable(true);
+        topAndDown.setDividerLocation(0.8);
+        topAndDown.setResizeWeight(.8);
+        topAndDown.setContinuousLayout(true);
+        
         mainPanel = createMainPanel();
-        treeAndMain.setRightComponent(mainPanel);
+        
+        logPanel = createLoggerPanel();
+        
+        topAndDown.setTopComponent(mainPanel);
+        topAndDown.setBottomComponent(logPanel);
+        
+        treeAndMain.setRightComponent(topAndDown);
 
         treeAndMain.setResizeWeight(.2);
         treeAndMain.setContinuousLayout(true);
@@ -423,6 +442,7 @@ public class MainFrame extends JFrame im
         setIconImage(JMeterUtils.getImage("jmeter.jpg").getImage());// $NON-NLS-1$
     }
 
+
     /**
      * Support for Test Plan Dnd
      * see BUG 52281 (when JDK6 will be minimum JDK target)
@@ -488,6 +508,22 @@ public class MainFrame extends JFrame im
     private JScrollPane createMainPanel() {
         return new JScrollPane();
     }
+    
+    /**
+     * Create at the down of the left a Console for Log events
+     * @return {@link LoggerPanel}
+     */
+    private LoggerPanel createLoggerPanel() {
+        LoggerPanel loggerPanel = new LoggerPanel();
+        loggerPanel.setMinimumSize(new Dimension(0, 100));
+        loggerPanel.setPreferredSize(new Dimension(0, 150));
+        LoggingManager.addLogTargetToRootLogger(loggerPanel);
+        GuiPackage guiInstance = GuiPackage.getInstance();
+        guiInstance.setLoggerPanel(loggerPanel);
+        guiInstance.getMenuItemLoggerPanel().getModel().setSelected(DISPLAY_LOGGER_PANEL);
+        loggerPanel.setVisible(DISPLAY_LOGGER_PANEL);
+        return loggerPanel;
+    }
 
     /**
      * Create and initialize the GUI representation of the test tree.

Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java?rev=1234478&r1=1234477&r2=1234478&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java Sun Jan 22 10:46:11 2012
@@ -60,6 +60,7 @@ public class ActionNames {
     public static final String INSERT_AFTER     = "drag_n_drop.insert_after";//$NON-NLS-1$
     public static final String INSERT_BEFORE    = "drag_n_drop.insert_before";//$NON-NLS-1$
     public static final String LAF_PREFIX       = "laf:"; // Look and Feel prefix
+    public static final String LOGGER_PANEL_ENABLE_DISABLE     = "logger_panel_enable_disable"; // $NON-NLS-1$
     public static final String MERGE            = "merge"; // $NON-NLS-1$
     public static final String OPEN             = "open"; // $NON-NLS-1$
     public static final String OPEN_RECENT      = "open_recent"; // $NON-NLS-1$

Added: jmeter/trunk/src/core/org/apache/jmeter/gui/action/LoggerPannelEnableDisable.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/action/LoggerPannelEnableDisable.java?rev=1234478&view=auto
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/action/LoggerPannelEnableDisable.java (added)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/action/LoggerPannelEnableDisable.java Sun Jan 22 10:46:11 2012
@@ -0,0 +1,74 @@
+/*
+ * 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 org.apache.jmeter.gui.action;
+
+import java.awt.event.ActionEvent;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.swing.JSplitPane;
+
+import org.apache.jmeter.gui.GuiPackage;
+
+/**
+ * Hide / unhide LoggerPanel.
+ *
+ */
+public class LoggerPannelEnableDisable implements Command {
+
+    private static final Set<String> commands = new HashSet<String>();
+
+    static {
+        commands.add(ActionNames.LOGGER_PANEL_ENABLE_DISABLE);
+    }
+
+    /**
+     * Constructor for object.
+     */
+    public LoggerPannelEnableDisable() {
+    }
+
+    /**
+     * Gets the ActionNames attribute of the action
+     *
+     * @return the ActionNames value
+     */
+    public Set<String> getActionNames() {
+        return commands;
+    }
+
+    /**
+     * This method performs the actual command processing.
+     *
+     * @param e
+     *            the generic UI action event
+     */
+    public void doAction(ActionEvent e) {
+        if (ActionNames.LOGGER_PANEL_ENABLE_DISABLE.equals(e.getActionCommand())) {
+            GuiPackage guiInstance = GuiPackage.getInstance();
+            if (guiInstance.getMenuItemLoggerPanel().getModel().isSelected()) {
+                guiInstance.getLoggerPanel().setVisible(true);
+                JSplitPane splitPane = ((JSplitPane)guiInstance.getLoggerPanel().getParent());
+                splitPane.setDividerLocation(0.8);
+            } else {
+                guiInstance.getLoggerPanel().setVisible(false);
+            }
+        }
+    }
+}

Propchange: jmeter/trunk/src/core/org/apache/jmeter/gui/action/LoggerPannelEnableDisable.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/util/JMeterMenuBar.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/util/JMeterMenuBar.java?rev=1234478&r1=1234477&r2=1234478&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/util/JMeterMenuBar.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/util/JMeterMenuBar.java Sun Jan 22 10:46:11 2012
@@ -282,11 +282,14 @@ public class JMeterMenuBar extends JMenu
         optionsMenu.add(lafMenu);
 
         JCheckBoxMenuItem menuToolBar = makeCheckBoxMenuItemRes("menu_toolbar", ActionNames.TOOLBAR); //$NON-NLS-1$
+        JCheckBoxMenuItem menuLoggerPanel = makeCheckBoxMenuItemRes("menu_logger_panel", ActionNames.LOGGER_PANEL_ENABLE_DISABLE); //$NON-NLS-1$
         GuiPackage guiInstance = GuiPackage.getInstance();
         if (guiInstance != null) { //avoid error in ant task tests (good way?)
             guiInstance.setMenuItemToolbar(menuToolBar);
+            guiInstance.setMenuItemLoggerPanel(menuLoggerPanel);
         }
         optionsMenu.add(menuToolBar);
+        optionsMenu.add(menuLoggerPanel);
         
         if (SSLManager.isSSLSupported()) {
             sslManager = makeMenuItemRes("sslmanager", 'S', ActionNames.SSL_MANAGER, KeyStrokes.SSL_MANAGER); //$NON-NLS-1$

Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties?rev=1234478&r1=1234477&r2=1234478&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties Sun Jan 22 10:46:11 2012
@@ -535,6 +535,7 @@ menu_fragments=Test Fragment
 menu_generative_controller=Sampler
 menu_listener=Listener
 menu_logic_controller=Logic Controller
+menu_logger_panel=Enable/Disable Log Viewer 
 menu_merge=Merge
 menu_modifiers=Modifiers
 menu_non_test_elements=Non-Test Elements

Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties?rev=1234478&r1=1234477&r2=1234478&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties Sun Jan 22 10:46:11 2012
@@ -529,6 +529,7 @@ menu_fragments=Fragment d'\u00E9l\u00E9m
 menu_generative_controller=Echantillons
 menu_listener=R\u00E9cepteurs
 menu_logic_controller=Contr\u00F4leurs Logiques
+menu_logger_panel=Activer/D\u00E9sactiver la console 
 menu_merge=Fusionner...
 menu_modifiers=Modificateurs
 menu_non_test_elements=El\u00E9ments hors test

Modified: jmeter/trunk/src/jorphan/org/apache/jorphan/logging/LoggingManager.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/jorphan/org/apache/jorphan/logging/LoggingManager.java?rev=1234478&r1=1234477&r2=1234478&view=diff
==============================================================================
--- jmeter/trunk/src/jorphan/org/apache/jorphan/logging/LoggingManager.java (original)
+++ jmeter/trunk/src/jorphan/org/apache/jorphan/logging/LoggingManager.java Sun Jan 22 10:46:11 2012
@@ -52,7 +52,7 @@ public final class LoggingManager {
      * Predefined format patterns, selected by the property log_format_type (see
      * jmeter.properties) The new-line is added later
      */
-    private static final String DEFAULT_PATTERN = "%{time:yyyy/MM/dd HH:mm:ss} %5.5{priority} - "  //$NON_NLS-1$
+    public static final String DEFAULT_PATTERN = "%{time:yyyy/MM/dd HH:mm:ss} %5.5{priority} - "  //$NON_NLS-1$
             + "%{category}: %{message} %{throwable}"; //$NON_NLS-1$
 
     private static final String PATTERN_THREAD_PREFIX = "%{time:yyyy/MM/dd HH:mm:ss} %5.5{priority} "  //$NON_NLS-1$
@@ -329,7 +329,7 @@ public final class LoggingManager {
      * @param targetFile
      *            (Writer)
      */
-    public static synchronized void setTarget(Writer targetFile) {
+    private static synchronized void setTarget(Writer targetFile) {
         if (target == null) {
             target = getTarget(targetFile, getFormat());
             isTargetSystemOut = isWriterSystemOut;
@@ -346,4 +346,14 @@ public final class LoggingManager {
     private static LogTarget getTarget(Writer targetFile, PatternFormatter fmt) {
         return new WriterTarget(targetFile, fmt);
     }
+
+    /**
+     * Add logTarget to root logger
+     * FIXME What's the clean way to add a LogTarget afterwards ?
+     * @param logTarget LogTarget
+     */
+    public static void addLogTargetToRootLogger(LogTarget logTarget) {
+        Hierarchy.getDefaultHierarchy().getRootLogger().setLogTargets(
+                new LogTarget[]{target, logTarget});
+    }
 }

Modified: jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1234478&r1=1234477&r2=1234478&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml (original)
+++ jmeter/trunk/xdocs/changes.xml Sun Jan 22 10:46:11 2012
@@ -427,6 +427,7 @@ Loads any additional properties found in
 <li>Bug 52471 - Improve Mirror Server performance by Using Pool of threads instead of launching a Thread for each request</li>
 <li>Resurrected OldSaveService to allow reading Avalon format JMX files (removed in 2.4)</li>
 <li>Add a dialog box to confirm removing the element(s) when Remove action is called</li>
+<li>Bug 41788 - Log viewer (console window) needed as an option</li>
 </ul>
 
 <h2>Non-functional changes</h2>



Re: svn commit: r1234478 - in /jmeter/trunk: bin/ src/core/org/apache/jmeter/gui/ src/core/org/apache/jmeter/gui/action/ src/core/org/apache/jmeter/gui/util/ src/core/org/apache/jmeter/resources/ src/jorphan/org/apache/jorphan/logging/ xdocs/

Posted by Milamber <mi...@apache.org>.
Philippe,

It's possible to include
        JSplitPane topAndDown = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
in setVisible true/false in
guiInstance.getLoggerPanel().setVisible(true);

In my opinion, it is not needed to see the vertical split all the time.

Thanks

Milamber

Le 22/01/2012 10:46, pmouawad@apache.org a ecrit :
> Author: pmouawad
> Date: Sun Jan 22 10:46:11 2012
> New Revision: 1234478
>
> URL: http://svn.apache.org/viewvc?rev=1234478&view=rev
> Log:
> Bug 41788 - Log viewer (console window) needed as an option
>
> Added:
>     jmeter/trunk/src/core/org/apache/jmeter/gui/LoggerPanel.java   (with props)
>     jmeter/trunk/src/core/org/apache/jmeter/gui/action/LoggerPannelEnableDisable.java   (with props)
> Modified:
>     jmeter/trunk/bin/jmeter.properties
>     jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java
>     jmeter/trunk/src/core/org/apache/jmeter/gui/MainFrame.java
>     jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java
>     jmeter/trunk/src/core/org/apache/jmeter/gui/util/JMeterMenuBar.java
>     jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
>     jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
>     jmeter/trunk/src/jorphan/org/apache/jorphan/logging/LoggingManager.java
>     jmeter/trunk/xdocs/changes.xml
>
> Modified: jmeter/trunk/bin/jmeter.properties
> URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/jmeter.properties?rev=1234478&r1=1234477&r2=1234478&view=diff
> ==============================================================================
> --- jmeter/trunk/bin/jmeter.properties (original)
> +++ jmeter/trunk/bin/jmeter.properties Sun Jan 22 10:46:11 2012
> @@ -121,6 +121,13 @@ jmeter.laf.mac=System
>  # See https://issues.apache.org/bugzilla/show_bug.cgi?id=52026 for details
>  # N.B. the laf can be defined in user.properties.
>  
> +# LoggerPanel display
> +# default to false
> +jmeter.loggerpanel.display=true
> +# Max characters kept in LoggerPanel, default to 80000 chars
> +# O means no limit
> +jmeter.loggerpanel.maxlength=5000
> +
>  # Toolbar display
>  # default:
>  #jmeter.toolbar.display=true
>
> Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java?rev=1234478&r1=1234477&r2=1234478&view=diff
> ==============================================================================
> --- jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java (original)
> +++ jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java Sun Jan 22 10:46:11 2012
> @@ -110,6 +110,17 @@ public final class GuiPackage implements
>  
>      /** The menu item toolbar. */
>      private JCheckBoxMenuItem menuToolBar;
> +
> +    /**
> +     * The LoggerPanel menu item
> +     */
> +    private JCheckBoxMenuItem menuItemLoggerPanel;
> +
> +    /**
> +     * Logger Panel reference
> +     */
> +    private LoggerPanel loggerPanel;
> +
>      
>      /**
>       * Private constructor to permit instantiation only from within this class.
> @@ -729,4 +740,35 @@ public final class GuiPackage implements
>          list.addAll(stoppables);
>          return list;
>      }
> +
> +    /**
> +     * Set the menu item LoggerPanel.
> +     * @param menuItemLoggerPanel
> +     */
> +    public void setMenuItemLoggerPanel(JCheckBoxMenuItem menuItemLoggerPanel) {
> +        this.menuItemLoggerPanel = menuItemLoggerPanel;
> +    }
> +    
> +    /**
> +     * Get the menu item LoggerPanel.
> +     *
> +     * @return the menu item LoggerPanel
> +     */
> +    public JCheckBoxMenuItem getMenuItemLoggerPanel() {
> +        return menuItemLoggerPanel;
> +    }
> +
> +    /**
> +     * @param loggerPanel LoggerPanel
> +     */
> +    public void setLoggerPanel(LoggerPanel loggerPanel) {
> +        this.loggerPanel = loggerPanel;
> +    }
> +
> +    /**
> +     * @return the loggerPanel
> +     */
> +    public LoggerPanel getLoggerPanel() {
> +        return loggerPanel;
> +    }
>  }
> \ No newline at end of file
>
> Added: jmeter/trunk/src/core/org/apache/jmeter/gui/LoggerPanel.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/LoggerPanel.java?rev=1234478&view=auto
> ==============================================================================
> --- jmeter/trunk/src/core/org/apache/jmeter/gui/LoggerPanel.java (added)
> +++ jmeter/trunk/src/core/org/apache/jmeter/gui/LoggerPanel.java Sun Jan 22 10:46:11 2012
> @@ -0,0 +1,109 @@
> +/*
> + * 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 org.apache.jmeter.gui;
> +
> +import java.awt.BorderLayout;
> +import java.awt.Dimension;
> +
> +import javax.swing.Box;
> +import javax.swing.JPanel;
> +import javax.swing.JScrollPane;
> +import javax.swing.JTextArea;
> +import javax.swing.SwingUtilities;
> +import javax.swing.border.Border;
> +import javax.swing.border.EmptyBorder;
> +
> +import org.apache.jmeter.util.JMeterUtils;
> +import org.apache.jorphan.logging.LoggingManager;
> +import org.apache.log.LogEvent;
> +import org.apache.log.LogTarget;
> +import org.apache.log.format.PatternFormatter;
> +
> +/**
> + * Panel that shows log events
> + */
> +public class LoggerPanel extends JPanel implements LogTarget {
> +
> +    /**
> +     * 
> +     */
> +    private static final long serialVersionUID = 6911128494402594429L;
> +    private JTextArea textArea;
> +    private PatternFormatter format;
> +
> +    // Limit length of log content
> +    private static final int LOGGER_PANEL_MAX_LENGTH =
> +            JMeterUtils.getPropDefault("jmeter.loggerpanel.maxlength", 80000); // $NON-NLS-1$
> +
> +    /**
> +     * 
> +     */
> +    public LoggerPanel() {
> +        init();
> +        format = new PatternFormatter(LoggingManager.DEFAULT_PATTERN + "\n");
> +    }
> +
> +    private void init() {
> +        this.setLayout(new BorderLayout());
> +
> +        // MAIN PANEL
> +        Border margin = new EmptyBorder(5, 5, 5, 5);
> +
> +        this.setBorder(margin);
> +        
> +        // TEXTAREA
> +        textArea = new JTextArea();
> +        textArea.setEditable(false);
> +        textArea.setLineWrap(false);
> +        JScrollPane areaScrollPane = new JScrollPane(textArea);
> +
> +        areaScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
> +        areaScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
> +
> +        Box mainPanel = Box.createVerticalBox();
> +        
> +        areaScrollPane.setPreferredSize(new Dimension(mainPanel.getWidth(),mainPanel.getHeight()));
> +        mainPanel.add(areaScrollPane);
> +        this.add(mainPanel, BorderLayout.CENTER); 
> +    }
> +
> +    /* (non-Javadoc)
> +     * @see org.apache.log.LogTarget#processEvent(org.apache.log.LogEvent)
> +     */
> +    public void processEvent(final LogEvent logEvent) {
> +        if(!GuiPackage.getInstance().getMenuItemLoggerPanel().getModel().isSelected()) {
> +            return;
> +        }
> +        
> +        SwingUtilities.invokeLater(new Runnable() {
> +            public void run() {
> +                synchronized (textArea) {
> +                    textArea.append(format.format(logEvent));
> +                    int currentLength = textArea.getText().length();
> +                    // If LOGGER_PANEL_MAX_LENGTH is 0, it means all log events are kept
> +                    if(LOGGER_PANEL_MAX_LENGTH != 0 && currentLength> LOGGER_PANEL_MAX_LENGTH) {
> +                        textArea.setText(textArea.getText().substring(Math.max(0, currentLength-LOGGER_PANEL_MAX_LENGTH), 
> +                                currentLength));
> +                    }
> +                    textArea.setCaretPosition(textArea.getText().length());
> +                }
> +            }
> +        });
> +    }
> +}
> \ No newline at end of file
>
> Propchange: jmeter/trunk/src/core/org/apache/jmeter/gui/LoggerPanel.java
> ------------------------------------------------------------------------------
>     svn:mime-type = text/plain
>
> Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/MainFrame.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/MainFrame.java?rev=1234478&r1=1234477&r2=1234478&view=diff
> ==============================================================================
> --- jmeter/trunk/src/core/org/apache/jmeter/gui/MainFrame.java (original)
> +++ jmeter/trunk/src/core/org/apache/jmeter/gui/MainFrame.java Sun Jan 22 10:46:11 2012
> @@ -104,6 +104,10 @@ public class MainFrame extends JFrame im
>      private static final boolean DISPLAY_TOOLBAR =
>              JMeterUtils.getPropDefault("jmeter.toolbar.display", true); // $NON-NLS-1$
>  
> +    // Allow display/hide LoggerPanel
> +    private static final boolean DISPLAY_LOGGER_PANEL =
> +            JMeterUtils.getPropDefault("jmeter.loggerpanel.display", false); // $NON-NLS-1$
> +
>      private static final Logger log = LoggingManager.getLoggerForClass();
>  
>      /** The menu bar. */
> @@ -115,6 +119,9 @@ public class MainFrame extends JFrame im
>      /** The panel where the test tree is shown. */
>      private JScrollPane treePanel;
>  
> +    /** The LOG panel. */
> +    private LoggerPanel logPanel;
> +
>      /** The test tree. */
>      private JTree tree;
>  
> @@ -407,8 +414,20 @@ public class MainFrame extends JFrame im
>          treePanel = createTreePanel();
>          treeAndMain.setLeftComponent(treePanel);
>  
> +        JSplitPane topAndDown = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
> +        topAndDown.setOneTouchExpandable(true);
> +        topAndDown.setDividerLocation(0.8);
> +        topAndDown.setResizeWeight(.8);
> +        topAndDown.setContinuousLayout(true);
> +        
>          mainPanel = createMainPanel();
> -        treeAndMain.setRightComponent(mainPanel);
> +        
> +        logPanel = createLoggerPanel();
> +        
> +        topAndDown.setTopComponent(mainPanel);
> +        topAndDown.setBottomComponent(logPanel);
> +        
> +        treeAndMain.setRightComponent(topAndDown);
>  
>          treeAndMain.setResizeWeight(.2);
>          treeAndMain.setContinuousLayout(true);
> @@ -423,6 +442,7 @@ public class MainFrame extends JFrame im
>          setIconImage(JMeterUtils.getImage("jmeter.jpg").getImage());// $NON-NLS-1$
>      }
>  
> +
>      /**
>       * Support for Test Plan Dnd
>       * see BUG 52281 (when JDK6 will be minimum JDK target)
> @@ -488,6 +508,22 @@ public class MainFrame extends JFrame im
>      private JScrollPane createMainPanel() {
>          return new JScrollPane();
>      }
> +    
> +    /**
> +     * Create at the down of the left a Console for Log events
> +     * @return {@link LoggerPanel}
> +     */
> +    private LoggerPanel createLoggerPanel() {
> +        LoggerPanel loggerPanel = new LoggerPanel();
> +        loggerPanel.setMinimumSize(new Dimension(0, 100));
> +        loggerPanel.setPreferredSize(new Dimension(0, 150));
> +        LoggingManager.addLogTargetToRootLogger(loggerPanel);
> +        GuiPackage guiInstance = GuiPackage.getInstance();
> +        guiInstance.setLoggerPanel(loggerPanel);
> +        guiInstance.getMenuItemLoggerPanel().getModel().setSelected(DISPLAY_LOGGER_PANEL);
> +        loggerPanel.setVisible(DISPLAY_LOGGER_PANEL);
> +        return loggerPanel;
> +    }
>  
>      /**
>       * Create and initialize the GUI representation of the test tree.
>
> Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java?rev=1234478&r1=1234477&r2=1234478&view=diff
> ==============================================================================
> --- jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java (original)
> +++ jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java Sun Jan 22 10:46:11 2012
> @@ -60,6 +60,7 @@ public class ActionNames {
>      public static final String INSERT_AFTER     = "drag_n_drop.insert_after";//$NON-NLS-1$
>      public static final String INSERT_BEFORE    = "drag_n_drop.insert_before";//$NON-NLS-1$
>      public static final String LAF_PREFIX       = "laf:"; // Look and Feel prefix
> +    public static final String LOGGER_PANEL_ENABLE_DISABLE     = "logger_panel_enable_disable"; // $NON-NLS-1$
>      public static final String MERGE            = "merge"; // $NON-NLS-1$
>      public static final String OPEN             = "open"; // $NON-NLS-1$
>      public static final String OPEN_RECENT      = "open_recent"; // $NON-NLS-1$
>
> Added: jmeter/trunk/src/core/org/apache/jmeter/gui/action/LoggerPannelEnableDisable.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/action/LoggerPannelEnableDisable.java?rev=1234478&view=auto
> ==============================================================================
> --- jmeter/trunk/src/core/org/apache/jmeter/gui/action/LoggerPannelEnableDisable.java (added)
> +++ jmeter/trunk/src/core/org/apache/jmeter/gui/action/LoggerPannelEnableDisable.java Sun Jan 22 10:46:11 2012
> @@ -0,0 +1,74 @@
> +/*
> + * 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 org.apache.jmeter.gui.action;
> +
> +import java.awt.event.ActionEvent;
> +import java.util.HashSet;
> +import java.util.Set;
> +
> +import javax.swing.JSplitPane;
> +
> +import org.apache.jmeter.gui.GuiPackage;
> +
> +/**
> + * Hide / unhide LoggerPanel.
> + *
> + */
> +public class LoggerPannelEnableDisable implements Command {
> +
> +    private static final Set<String> commands = new HashSet<String>();
> +
> +    static {
> +        commands.add(ActionNames.LOGGER_PANEL_ENABLE_DISABLE);
> +    }
> +
> +    /**
> +     * Constructor for object.
> +     */
> +    public LoggerPannelEnableDisable() {
> +    }
> +
> +    /**
> +     * Gets the ActionNames attribute of the action
> +     *
> +     * @return the ActionNames value
> +     */
> +    public Set<String> getActionNames() {
> +        return commands;
> +    }
> +
> +    /**
> +     * This method performs the actual command processing.
> +     *
> +     * @param e
> +     *            the generic UI action event
> +     */
> +    public void doAction(ActionEvent e) {
> +        if (ActionNames.LOGGER_PANEL_ENABLE_DISABLE.equals(e.getActionCommand())) {
> +            GuiPackage guiInstance = GuiPackage.getInstance();
> +            if (guiInstance.getMenuItemLoggerPanel().getModel().isSelected()) {
> +                guiInstance.getLoggerPanel().setVisible(true);
> +                JSplitPane splitPane = ((JSplitPane)guiInstance.getLoggerPanel().getParent());
> +                splitPane.setDividerLocation(0.8);
> +            } else {
> +                guiInstance.getLoggerPanel().setVisible(false);
> +            }
> +        }
> +    }
> +}
>
> Propchange: jmeter/trunk/src/core/org/apache/jmeter/gui/action/LoggerPannelEnableDisable.java
> ------------------------------------------------------------------------------
>     svn:mime-type = text/plain
>
> Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/util/JMeterMenuBar.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/util/JMeterMenuBar.java?rev=1234478&r1=1234477&r2=1234478&view=diff
> ==============================================================================
> --- jmeter/trunk/src/core/org/apache/jmeter/gui/util/JMeterMenuBar.java (original)
> +++ jmeter/trunk/src/core/org/apache/jmeter/gui/util/JMeterMenuBar.java Sun Jan 22 10:46:11 2012
> @@ -282,11 +282,14 @@ public class JMeterMenuBar extends JMenu
>          optionsMenu.add(lafMenu);
>  
>          JCheckBoxMenuItem menuToolBar = makeCheckBoxMenuItemRes("menu_toolbar", ActionNames.TOOLBAR); //$NON-NLS-1$
> +        JCheckBoxMenuItem menuLoggerPanel = makeCheckBoxMenuItemRes("menu_logger_panel", ActionNames.LOGGER_PANEL_ENABLE_DISABLE); //$NON-NLS-1$
>          GuiPackage guiInstance = GuiPackage.getInstance();
>          if (guiInstance != null) { //avoid error in ant task tests (good way?)
>              guiInstance.setMenuItemToolbar(menuToolBar);
> +            guiInstance.setMenuItemLoggerPanel(menuLoggerPanel);
>          }
>          optionsMenu.add(menuToolBar);
> +        optionsMenu.add(menuLoggerPanel);
>          
>          if (SSLManager.isSSLSupported()) {
>              sslManager = makeMenuItemRes("sslmanager", 'S', ActionNames.SSL_MANAGER, KeyStrokes.SSL_MANAGER); //$NON-NLS-1$
>
> Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties?rev=1234478&r1=1234477&r2=1234478&view=diff
> ==============================================================================
> --- jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties (original)
> +++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties Sun Jan 22 10:46:11 2012
> @@ -535,6 +535,7 @@ menu_fragments=Test Fragment
>  menu_generative_controller=Sampler
>  menu_listener=Listener
>  menu_logic_controller=Logic Controller
> +menu_logger_panel=Enable/Disable Log Viewer 
>  menu_merge=Merge
>  menu_modifiers=Modifiers
>  menu_non_test_elements=Non-Test Elements
>
> Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties?rev=1234478&r1=1234477&r2=1234478&view=diff
> ==============================================================================
> --- jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties (original)
> +++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties Sun Jan 22 10:46:11 2012
> @@ -529,6 +529,7 @@ menu_fragments=Fragment d'\u00E9l\u00E9m
>  menu_generative_controller=Echantillons
>  menu_listener=R\u00E9cepteurs
>  menu_logic_controller=Contr\u00F4leurs Logiques
> +menu_logger_panel=Activer/D\u00E9sactiver la console 
>  menu_merge=Fusionner...
>  menu_modifiers=Modificateurs
>  menu_non_test_elements=El\u00E9ments hors test
>
> Modified: jmeter/trunk/src/jorphan/org/apache/jorphan/logging/LoggingManager.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/jorphan/org/apache/jorphan/logging/LoggingManager.java?rev=1234478&r1=1234477&r2=1234478&view=diff
> ==============================================================================
> --- jmeter/trunk/src/jorphan/org/apache/jorphan/logging/LoggingManager.java (original)
> +++ jmeter/trunk/src/jorphan/org/apache/jorphan/logging/LoggingManager.java Sun Jan 22 10:46:11 2012
> @@ -52,7 +52,7 @@ public final class LoggingManager {
>       * Predefined format patterns, selected by the property log_format_type (see
>       * jmeter.properties) The new-line is added later
>       */
> -    private static final String DEFAULT_PATTERN = "%{time:yyyy/MM/dd HH:mm:ss} %5.5{priority} - "  //$NON_NLS-1$
> +    public static final String DEFAULT_PATTERN = "%{time:yyyy/MM/dd HH:mm:ss} %5.5{priority} - "  //$NON_NLS-1$
>              + "%{category}: %{message} %{throwable}"; //$NON_NLS-1$
>  
>      private static final String PATTERN_THREAD_PREFIX = "%{time:yyyy/MM/dd HH:mm:ss} %5.5{priority} "  //$NON_NLS-1$
> @@ -329,7 +329,7 @@ public final class LoggingManager {
>       * @param targetFile
>       *            (Writer)
>       */
> -    public static synchronized void setTarget(Writer targetFile) {
> +    private static synchronized void setTarget(Writer targetFile) {
>          if (target == null) {
>              target = getTarget(targetFile, getFormat());
>              isTargetSystemOut = isWriterSystemOut;
> @@ -346,4 +346,14 @@ public final class LoggingManager {
>      private static LogTarget getTarget(Writer targetFile, PatternFormatter fmt) {
>          return new WriterTarget(targetFile, fmt);
>      }
> +
> +    /**
> +     * Add logTarget to root logger
> +     * FIXME What's the clean way to add a LogTarget afterwards ?
> +     * @param logTarget LogTarget
> +     */
> +    public static void addLogTargetToRootLogger(LogTarget logTarget) {
> +        Hierarchy.getDefaultHierarchy().getRootLogger().setLogTargets(
> +                new LogTarget[]{target, logTarget});
> +    }
>  }
>
> Modified: jmeter/trunk/xdocs/changes.xml
> URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1234478&r1=1234477&r2=1234478&view=diff
> ==============================================================================
> --- jmeter/trunk/xdocs/changes.xml (original)
> +++ jmeter/trunk/xdocs/changes.xml Sun Jan 22 10:46:11 2012
> @@ -427,6 +427,7 @@ Loads any additional properties found in
>  <li>Bug 52471 - Improve Mirror Server performance by Using Pool of threads instead of launching a Thread for each request</li>
>  <li>Resurrected OldSaveService to allow reading Avalon format JMX files (removed in 2.4)</li>
>  <li>Add a dialog box to confirm removing the element(s) when Remove action is called</li>
> +<li>Bug 41788 - Log viewer (console window) needed as an option</li>
>  </ul>
>  
>  <h2>Non-functional changes</h2>
>
>
>
>