Revert to (mostly) previous version that still includes StatusConsoleListener

git-svn-id: https://svn.apache.org/repos/asf/logging/log4j/log4j2/branches/LOG4J2-609@1610903 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfiguration.java
index 9598a1d..c22c50c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfiguration.java
@@ -34,6 +34,7 @@
 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
 import org.apache.logging.log4j.core.config.plugins.util.ResolverUtil;
+import org.apache.logging.log4j.core.config.status.StatusConfiguration;
 import org.apache.logging.log4j.core.util.Patterns;
 
 import com.fasterxml.jackson.core.JsonParser;
@@ -68,11 +69,19 @@
                 }
             }
             processAttributes(rootNode, root);
+            final StatusConfiguration statusConfig = new StatusConfiguration().withVerboseClasses(VERBOSE_CLASSES)
+                    .withStatus(getDefaultStatus());
             for (final Map.Entry<String, String> entry : rootNode.getAttributes().entrySet()) {
                 final String key = entry.getKey();
                 final String value = getStrSubstitutor().replace(entry.getValue());
-                if ("shutdownHook".equalsIgnoreCase(key)) {
+                if ("status".equalsIgnoreCase(key)) {
+                    statusConfig.withStatus(value);
+                } else if ("dest".equalsIgnoreCase(key)) {
+                    statusConfig.withDestination(value);
+                } else if ("shutdownHook".equalsIgnoreCase(key)) {
                     isShutdownHookEnabled = !"disable".equalsIgnoreCase(value);
+                } else if ("verbose".equalsIgnoreCase(entry.getKey())) {
+                    statusConfig.withVerbosity(value);
                 } else if ("packages".equalsIgnoreCase(key)) {
                     final String[] packages = value.split(Patterns.COMMA_SEPARATOR);
                     for (final String p : packages) {
@@ -89,6 +98,7 @@
                     createAdvertiser(value, configSource, buffer, "application/json");
                 }
             }
+            statusConfig.initialize();
             if (getName() == null) {
                 setName(configSource.getLocation());
             }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConfiguration.java
new file mode 100644
index 0000000..60abf2f
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConfiguration.java
@@ -0,0 +1,202 @@
+/*

+ * 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.logging.log4j.core.config.status;

+

+import java.util.Collection;

+import java.util.Collections;

+import java.util.LinkedList;

+

+import org.apache.logging.log4j.Level;

+import org.apache.logging.log4j.status.StatusListener;

+import org.apache.logging.log4j.status.StatusLogger;

+

+/**

+ * Configuration for setting up {@link StatusConsoleListener} instances.

+ */

+public class StatusConfiguration {

+

+    private static final Level DEFAULT_STATUS = Level.ERROR;

+    private static final Verbosity DEFAULT_VERBOSITY = Verbosity.QUIET;

+

+    private final Collection<String> errorMessages = Collections.synchronizedCollection(new LinkedList<String>());

+    private final StatusLogger logger = StatusLogger.getLogger();

+

+    private volatile boolean initialized = false;

+

+    private Class<? extends StatusConsoleListener> destination = StatusStdOutListener.class;

+    private Level status = DEFAULT_STATUS;

+    private Verbosity verbosity = DEFAULT_VERBOSITY;

+    private String[] verboseClasses;

+

+    /**

+     * Specifies how verbose the StatusLogger should be.

+     */

+    public static enum Verbosity {

+        QUIET, VERBOSE;

+

+        /**

+         * Parses the verbosity property into an enum.

+         *

+         * @param value property value to parse.

+         * @return enum corresponding to value, or QUIET by default.

+         */

+        public static Verbosity toVerbosity(final String value) {

+            return Boolean.parseBoolean(value) ? VERBOSE : QUIET;

+        }

+    }

+

+    /**

+     * Logs an error message to the StatusLogger. If the StatusLogger hasn't been set up yet, queues the message to be

+     * logged after initialization.

+     *

+     * @param message error message to log.

+     */

+    public void error(final String message) {

+        if (!this.initialized) {

+            this.errorMessages.add(message);

+        } else {

+            this.logger.error(message);

+        }

+    }

+

+    /**

+     * Specifies the destination for StatusLogger events. This can be {@code out} (default) for using

+     * {@link System#out standard out}, {@code err} for using {@link System#err standard error}, or a file URI to

+     * which log events will be written. If the provided URI is invalid, then the default destination of standard

+     * out will be used.

+     *

+     * @param destination where status log messages should be output.

+     * @return {@code this}

+     */

+    public StatusConfiguration withDestination(final String destination) {

+    	if ("out".equalsIgnoreCase(destination)) {

+    		this.destination = StatusStdOutListener.class;

+    	} else if ("err".equalsIgnoreCase(destination)) {

+    		this.destination = StatusStdErrListener.class;

+    	} else {

+    		this.error("Invalid destination [" + destination + "]. Only 'out' or 'err' are supported. Defaulting to 'out'.");

+    		this.destination = StatusStdOutListener.class;

+    	}

+        return this;

+    }

+

+    /**

+     * Specifies the logging level by name to use for filtering StatusLogger messages.

+     *

+     * @param status name of logger level to filter below.

+     * @return {@code this}

+     * @see Level

+     */

+    public StatusConfiguration withStatus(final String status) {

+        this.status = Level.toLevel(status, null);

+        if (this.status == null) {

+            this.error("Invalid status level specified: " + status + ". Defaulting to ERROR.");

+            this.status = Level.ERROR;

+        }

+        return this;

+    }

+

+    /**

+     * Specifies the logging level to use for filtering StatusLogger messages.

+     *

+     * @param status logger level to filter below.

+     * @return {@code this}

+     */

+    public StatusConfiguration withStatus(final Level status) {

+        this.status = status;

+        return this;

+    }

+

+    /**

+     * Specifies the verbosity level to log at. This only applies to classes configured by

+     * {@link #withVerboseClasses(String...) verboseClasses}.

+     *

+     * @param verbosity basic filter for status logger messages.

+     * @return {@code this}

+     */

+    public StatusConfiguration withVerbosity(final String verbosity) {

+        this.verbosity = Verbosity.toVerbosity(verbosity);

+        return this;

+    }

+

+    /**

+     * Specifies which class names to filter if the configured verbosity level is QUIET.

+     *

+     * @param verboseClasses names of classes to filter if not using VERBOSE.

+     * @return {@code this}

+     */

+    public StatusConfiguration withVerboseClasses(final String... verboseClasses) {

+        this.verboseClasses = verboseClasses;

+        return this;

+    }

+

+    /**

+     * Configures and initializes the StatusLogger using the configured options in this instance.

+     */

+    public void initialize() {

+        if (!this.initialized) {

+            if (this.status == Level.OFF) {

+                this.initialized = true;

+            } else {

+                final boolean configured = configureExistingStatusConsoleListener();

+                if (!configured) {

+                    registerNewStatusConsoleListener();

+                }

+                migrateSavedLogMessages();

+            }

+        }

+    }

+

+    private boolean configureExistingStatusConsoleListener() {

+        boolean configured = false;

+        for (final StatusListener statusListener : this.logger.getListeners()) {

+        	if (this.destination.isInstance(statusListener)) {

+                final StatusConsoleListener listener = (StatusConsoleListener) statusListener;

+                listener.setStatusLevel(this.status);

+                if (this.verbosity == Verbosity.QUIET) {

+                    listener.setFilters(this.verboseClasses);

+                }

+                configured = true;

+            }

+        }

+        return configured;

+    }

+

+

+    private void registerNewStatusConsoleListener() {

+        StatusConsoleListener listener;

+		try {

+			listener = this.destination.newInstance();

+	        listener.setStatusLevel(this.status);

+	        if (this.verbosity == Verbosity.QUIET) {

+	            listener.setFilters(this.verboseClasses);

+	        }

+	        this.logger.registerListener(listener);

+		} catch (ReflectiveOperationException e) {

+			logger.error("Cannot create listener of type " + destination.getClass());

+		}

+    }

+

+    private void migrateSavedLogMessages() {

+        for (final String message : this.errorMessages) {

+            this.logger.error(message);

+        }

+        this.initialized = true;

+        this.errorMessages.clear();

+    }

+}
\ No newline at end of file
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConsoleListener.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConsoleListener.java
new file mode 100644
index 0000000..d029cbb
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConsoleListener.java
@@ -0,0 +1,86 @@
+/*

+ * 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.logging.log4j.core.config.status;

+

+import java.io.IOException;

+

+import org.apache.logging.log4j.Level;

+import org.apache.logging.log4j.status.StatusData;

+import org.apache.logging.log4j.status.StatusListener;

+

+/**

+ * StatusListener that writes to the Console.

+ */

+public abstract class StatusConsoleListener implements StatusListener {

+

+    protected Level level;

+    private String[] filters = null;

+

+    /**

+     * Creates the StatusConsoleListener using the supplied Level. 

+     */

+    public StatusConsoleListener() {

+        this(Level.FATAL);

+    }

+

+    /**

+     * Creates the StatusConsoleListener using the supplied Level. 

+     * @param level The Level of status messages that should appear on the console.

+     */

+    public StatusConsoleListener(final Level level) {

+        this.level = level;

+    }

+

+    /**

+     * Sets the level to a new value.

+     * @param level The new Level.

+     */

+    public void setStatusLevel(final Level level) {

+        this.level = level;

+    }

+

+    @Override

+    public Level getStatusLevel() {

+    	return level;

+    }

+

+	/**

+     * Adds package name filters to exclude.

+     * @param filters An array of package names to exclude.

+     */

+    public void setFilters(final String... filters) {

+        this.filters = filters;

+    }

+

+    protected boolean isEnabledFor(final StatusData data) {

+        if (filters == null) {

+        	return true;

+        }

+        final String caller = data.getStackTraceElement().getClassName();

+        for (final String filter : filters) {

+            if (caller.startsWith(filter)) {

+                return true;

+            }

+        }

+        return false;

+    }

+

+    @Override

+    public void close() throws IOException {

+        // don't close system streams

+    }

+}

diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusStdErrListener.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusStdErrListener.java
new file mode 100644
index 0000000..59bd007
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusStdErrListener.java
@@ -0,0 +1,14 @@
+package org.apache.logging.log4j.core.config.status;

+

+import org.apache.logging.log4j.status.StatusData;

+

+public class StatusStdErrListener extends StatusConsoleListener {

+

+	@Override

+	public void log(StatusData data) {

+        if (isEnabledFor(data)) {

+            System.err.println(data.getFormattedStatus());

+        }

+	}

+

+}

diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusStdOutListener.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusStdOutListener.java
new file mode 100644
index 0000000..83631e1
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusStdOutListener.java
@@ -0,0 +1,14 @@
+package org.apache.logging.log4j.core.config.status;

+

+import org.apache.logging.log4j.status.StatusData;

+

+public class StatusStdOutListener extends StatusConsoleListener {

+

+	@Override

+	public void log(StatusData data) {

+        if (isEnabledFor(data)) {

+            System.out.println(data.getFormattedStatus());

+        }

+	}

+

+}

diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
index 309bf66..eadcbbc 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
@@ -43,6 +43,7 @@
 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
 import org.apache.logging.log4j.core.config.plugins.util.ResolverUtil;
+import org.apache.logging.log4j.core.config.status.StatusConfiguration;
 import org.apache.logging.log4j.core.util.Loader;
 import org.apache.logging.log4j.core.util.Patterns;
 import org.w3c.dom.Attr;
@@ -133,11 +134,19 @@
             final Document document = newDocumentBuilder().parse(source);
             rootElement = document.getDocumentElement();
             final Map<String, String> attrs = processAttributes(rootNode, rootElement);
+            final StatusConfiguration statusConfig = new StatusConfiguration().withVerboseClasses(VERBOSE_CLASSES)
+                    .withStatus(getDefaultStatus());
             for (final Map.Entry<String, String> entry : attrs.entrySet()) {
                 final String key = entry.getKey();
                 final String value = getStrSubstitutor().replace(entry.getValue());
-                if ("shutdownHook".equalsIgnoreCase(key)) {
+                if ("status".equalsIgnoreCase(key)) {
+                    statusConfig.withStatus(value);
+                } else if ("dest".equalsIgnoreCase(key)) {
+                    statusConfig.withDestination(value);
+                } else if ("shutdownHook".equalsIgnoreCase(key)) {
                     isShutdownHookEnabled = !"disable".equalsIgnoreCase(value);
+                } else if ("verbose".equalsIgnoreCase(key)) {
+                    statusConfig.withVerbosity(value);
                 } else if ("packages".equalsIgnoreCase(key)) {
                     final String[] packages = value.split(Patterns.COMMA_SEPARATOR);
                     for (final String p : packages) {
@@ -158,6 +167,7 @@
                     createAdvertiser(value, configSource, buffer, "text/xml");
                 }
             }
+            statusConfig.initialize();
         } catch (final SAXException domEx) {
             LOGGER.error("Error parsing " + configSource.getLocation(), domEx);
         } catch (final IOException ioe) {
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CustomConfigurationTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CustomConfigurationTest.java
index 1146664..9b12394 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CustomConfigurationTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CustomConfigurationTest.java
@@ -69,7 +69,7 @@
         assertTrue("Configuration is not an XmlConfiguration", config instanceof XmlConfiguration);
         for (final StatusListener listener : StatusLogger.getLogger().getListeners()) {
             if (listener instanceof StatusConsoleListener) {
-                assertSame(((StatusConsoleListener) listener).getLevel(), Level.INFO);
+                assertSame(((StatusConsoleListener) listener).getStatusLevel(), Level.INFO);
                 break;
             }
         }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueAppenderTest.java
index b51d8b0..7710d71 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueAppenderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueAppenderTest.java
@@ -59,7 +59,7 @@
     public static void setupClass() throws Exception {
         // MockContextFactory becomes the primary JNDI provider
         final StatusStdOutListener listener = new StatusStdOutListener();
-        listener.setLevel(Level.ERROR);
+        listener.setStatusLevel(Level.ERROR);
         StatusLogger.getLogger().registerListener(listener);
         MockContextFactory.setAsInitial();
         context = new InitialContext();
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueFailoverTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueFailoverTest.java
index ed6e284..938916b 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueFailoverTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueFailoverTest.java
@@ -87,7 +87,7 @@
     private static void setupQueue() throws Exception {
         // MockContextFactory becomes the primary JNDI provider
         final StatusStdOutListener listener = new StatusStdOutListener();
-        listener.setLevel(Level.ERROR);
+        listener.setStatusLevel(Level.ERROR);
         StatusLogger.getLogger().registerListener(listener);
         MockContextFactory.setAsInitial();
         context = new InitialContext();
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueTest.java
index 6881ca6..5a6b055 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueTest.java
@@ -65,7 +65,7 @@
     public static void setupClass() throws Exception {
         // MockContextFactory becomes the primary JNDI provider
         final StatusStdOutListener listener = new StatusStdOutListener();
-        listener.setLevel(Level.ERROR);
+        listener.setStatusLevel(Level.ERROR);
         StatusLogger.getLogger().registerListener(listener);
         MockContextFactory.setAsInitial();
         context = new InitialContext();
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicFailoverTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicFailoverTest.java
index 47f811e..1ffcb0c 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicFailoverTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicFailoverTest.java
@@ -86,7 +86,7 @@
     private static void setupQueue() throws Exception {
         // MockContextFactory becomes the primary JNDI provider
         final StatusStdOutListener listener = new StatusStdOutListener();
-        listener.setLevel(Level.ERROR);
+        listener.setStatusLevel(Level.ERROR);
         StatusLogger.getLogger().registerListener(listener);
         MockContextFactory.setAsInitial();
         context = new InitialContext();
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicTest.java
index 3565c40..0029fb6 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicTest.java
@@ -65,7 +65,7 @@
     public static void setupClass() throws Exception {
         // MockContextFactory becomes the primary JNDI provider
         final StatusStdOutListener listener = new StatusStdOutListener();
-        listener.setLevel(Level.ERROR);
+        listener.setStatusLevel(Level.ERROR);
         StatusLogger.getLogger().registerListener(listener);
         MockContextFactory.setAsInitial();
         context = new InitialContext();