[logback-dev] svn commit: r1852 - in logback/trunk: logback-access/src/main/java/ch/qos/logback/access/jetty logback-access/src/main/java/ch/qos/logback/access/spi logback-access/src/main/java/ch/qos/logback/access/tomcat logback-classic/src/main/java/ch/qos/logback/classic logback-classic/src/test/java/ch/qos/logback/classic logback-classic/src/test/java/ch/qos/logback/classic/control logback-core/src/main/java/ch/qos/logback/core/spi logback-core/src/test/java/ch/qos/logback/core logback-core/src/test/java/ch/qos/logback/core/spi
noreply.ceki at qos.ch
noreply.ceki at qos.ch
Mon Oct 20 20:51:03 CEST 2008
Author: ceki
Date: Mon Oct 20 20:51:02 2008
New Revision: 1852
Added:
logback/trunk/logback-core/src/test/java/ch/qos/logback/core/spi/
logback/trunk/logback-core/src/test/java/ch/qos/logback/core/spi/AppenderAttachableImplTest.java
logback/trunk/logback-core/src/test/java/ch/qos/logback/core/spi/PackageTest.java
Modified:
logback/trunk/logback-access/src/main/java/ch/qos/logback/access/jetty/RequestLogImpl.java
logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/AccessContext.java
logback/trunk/logback-access/src/main/java/ch/qos/logback/access/tomcat/LogbackValve.java
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/Logger.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/HLogger.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/control/ControlLogger.java
logback/trunk/logback-core/src/main/java/ch/qos/logback/core/spi/AppenderAttachable.java
logback/trunk/logback-core/src/main/java/ch/qos/logback/core/spi/AppenderAttachableImpl.java
logback/trunk/logback-core/src/test/java/ch/qos/logback/core/AllCoreTest.java
Log:
- detachAppender in AppenderAttachable now returns a boolean instead of an Appender.
- iteratorForAppenders() in AppenderAttachable now returns Iterator<Appender<E>> instead of just Iterator
- modified Logger to invoke callAppender without synchronization on this
- AppenderAttachableImpl modified to take advantage of the fact that reads occur much more
often than writes
- associated test cases
Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/jetty/RequestLogImpl.java
==============================================================================
--- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/jetty/RequestLogImpl.java (original)
+++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/jetty/RequestLogImpl.java Mon Oct 20 20:51:02 2008
@@ -166,7 +166,7 @@
getStatusManager().add(
new InfoStatus("RequestLog added to RequestLogRegistry with name: "
+ getName(), this));
-
+
started = true;
} catch (JoranException e) {
@@ -198,7 +198,7 @@
public boolean isStopping() {
return false;
}
-
+
public boolean isStopped() {
return !started;
}
@@ -211,7 +211,7 @@
aai.addAppender(newAppender);
}
- public Iterator iteratorForAppenders() {
+ public Iterator<Appender<AccessEvent>> iteratorForAppenders() {
return aai.iteratorForAppenders();
}
@@ -232,7 +232,7 @@
return aai.detachAppender(appender);
}
- public Appender<AccessEvent> detachAppender(String name) {
+ public boolean detachAppender(String name) {
return aai.detachAppender(name);
}
Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/AccessContext.java
==============================================================================
--- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/AccessContext.java (original)
+++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/AccessContext.java Mon Oct 20 20:51:02 2008
@@ -39,7 +39,7 @@
return aai.detachAppender(appender);
}
- public Appender<AccessEvent> detachAppender(String name) {
+ public boolean detachAppender(String name) {
return aai.detachAppender(name);
}
@@ -51,7 +51,7 @@
return aai.isAttached(appender);
}
- public Iterator iteratorForAppenders() {
+ public Iterator<Appender<AccessEvent>> iteratorForAppenders() {
return aai.iteratorForAppenders();
}
Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/tomcat/LogbackValve.java
==============================================================================
--- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/tomcat/LogbackValve.java (original)
+++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/tomcat/LogbackValve.java Mon Oct 20 20:51:02 2008
@@ -148,7 +148,7 @@
aai.addAppender(newAppender);
}
- public Iterator iteratorForAppenders() {
+ public Iterator<Appender<AccessEvent>> iteratorForAppenders() {
return aai.iteratorForAppenders();
}
@@ -169,7 +169,7 @@
return aai.detachAppender(appender);
}
- public Appender<AccessEvent> detachAppender(String name) {
+ public boolean detachAppender(String name) {
return aai.detachAppender(name);
}
Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/Logger.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/Logger.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/Logger.java Mon Oct 20 20:51:02 2008
@@ -66,6 +66,26 @@
*/
private List<Logger> childrenList;
+ /**
+ * It is assumed that once the 'aai' variable is set to a non-null value, it
+ * will never be reset to null. it is further assumed that only place where
+ * the 'aai'ariable is set is within the addAppender method. This method is
+ * synchronized on 'this' (Logger) protecting against simultaneous
+ * re-configuration of this logger (a very unlikely scenario).
+ *
+ * <p>
+ * It is further assumed that the AppenderAttachableImpl is responsible for
+ * its internal synchronization and thread safety. Thus, we can get away with
+ * *not* synchronizing on the 'aai' (check null/ read) because
+ * <p>
+ * 1) the 'aai' variable is immutable once set to non-null
+ * <p>
+ * 2) 'aai' is getAndSet only within addAppender which is synchronized
+ * <p>
+ * 3) all the other methods check whether 'aai' is null
+ * <p>
+ * 4) AppenderAttachableImpl is thread safe
+ */
private transient AppenderAttachableImpl<LoggingEvent> aai;
/**
* Additivity is set to true by default, that is children inherit the
@@ -193,7 +213,6 @@
if (level == null) {
effectiveLevelInt = newParentLevel.levelInt;
-
// propagate the parent levelInt change to this logger's children
if (childrenList != null) {
int len = childrenList.size();
@@ -209,19 +228,21 @@
* Remove all previously added appenders from this logger instance. <p/> This
* is useful when re-reading configuration information.
*/
- public synchronized void detachAndStopAllAppenders() {
+ public void detachAndStopAllAppenders() {
if (aai != null) {
aai.detachAndStopAllAppenders();
}
}
- public synchronized Appender<LoggingEvent> detachAppender(String name) {
+ public boolean detachAppender(String name) {
if (aai == null) {
- return null;
+ return false;
}
return aai.detachAppender(name);
}
+ // this method MUST be synchronized. See comments on 'aai' field for further
+ // details.
public synchronized void addAppender(Appender<LoggingEvent> newAppender) {
if (aai == null) {
aai = new AppenderAttachableImpl<LoggingEvent>();
@@ -236,7 +257,8 @@
return aai.isAttached(appender);
}
- public synchronized Iterator iteratorForAppenders() {
+ @SuppressWarnings("unchecked")
+ public Iterator<Appender<LoggingEvent>> iteratorForAppenders() {
if (aai == null) {
return Collections.EMPTY_LIST.iterator();
}
@@ -254,22 +276,16 @@
* Invoke all the appenders of this logger.
*
* @param event
- * The event to log
+ * The event to log
*/
public void callAppenders(LoggingEvent event) {
int writes = 0;
- // System.out.println("callAppenders");
for (Logger l = this; l != null; l = l.parent) {
- // System.out.println("l="+l.getName());
- // Protected against simultaneous call to addAppender, removeAppender,...
- synchronized (l) {
- writes += l.appendLoopOnAppenders(event);
- if (!l.additive) {
- break;
- }
+ writes += l.appendLoopOnAppenders(event);
+ if (!l.additive) {
+ break;
}
}
-
// No appenders in hierarchy
if (writes == 0) {
loggerContext.noAppenderDefinedWarning(this);
@@ -277,17 +293,17 @@
}
private int appendLoopOnAppenders(LoggingEvent event) {
- int size = 0;
if (aai != null) {
- size = aai.appendLoopOnAppenders(event);
+ return aai.appendLoopOnAppenders(event);
+ } else {
+ return 0;
}
- return size;
}
/**
* Remove the appender passed as parameter form the list of appenders.
*/
- public synchronized boolean detachAppender(Appender appender) {
+ public boolean detachAppender(Appender appender) {
if (aai == null) {
return false;
}
@@ -304,9 +320,9 @@
* logger.
*
* @param lastPart
- * the suffix (i.e. last part) of the child logger
- * name. This parameter may not include dots, i.e. the
- * logger separator character.
+ * the suffix (i.e. last part) of the child logger name. This
+ * parameter may not include dots, i.e. the logger separator
+ * character.
* @return
*/
Logger createChildByLastNamePart(final String lastPart) {
Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/HLogger.java
==============================================================================
--- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/HLogger.java (original)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/HLogger.java Mon Oct 20 20:51:02 2008
@@ -25,6 +25,8 @@
public class HLogger extends MarkerIgnoringBase {
+ private static final long serialVersionUID = 1L;
+
static int instanceCount = 0;
/**
Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/control/ControlLogger.java
==============================================================================
--- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/control/ControlLogger.java (original)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/control/ControlLogger.java Mon Oct 20 20:51:02 2008
@@ -17,6 +17,8 @@
* See javadoc for ControlLoggerContext.
*/
public class ControlLogger extends MarkerIgnoringBase {
+
+ private static final long serialVersionUID = 1L;
final ControlLogger parent;
final String name;
Level level;
Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/spi/AppenderAttachable.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/spi/AppenderAttachable.java (original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/spi/AppenderAttachable.java Mon Oct 20 20:51:02 2008
@@ -27,7 +27,7 @@
/**
* Get an iterator for appenders contained in the parent object.
*/
- public Iterator iteratorForAppenders();
+ public Iterator<Appender<E>> iteratorForAppenders();
/**
* Get an appender by name.
@@ -41,9 +41,9 @@
public boolean isAttached(Appender<E> appender);
/**
- * Detach all previously added appenders.
+ * Detach and stop all previously added appenders.
*/
- void detachAndStopAllAppenders();
+ void detachAndStopAllAppenders();
/**
* Detach the appender passed as parameter from the list of appenders.
@@ -54,5 +54,5 @@
* Detach the appender with the name passed as parameter from the list of
* appenders.
*/
- Appender<E> detachAppender(String name);
+ boolean detachAppender(String name);
}
Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/spi/AppenderAttachableImpl.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/spi/AppenderAttachableImpl.java (original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/spi/AppenderAttachableImpl.java Mon Oct 20 20:51:02 2008
@@ -9,9 +9,8 @@
*/
package ch.qos.logback.core.spi;
-import java.util.ArrayList;
import java.util.Iterator;
-import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
import ch.qos.logback.core.Appender;
@@ -22,20 +21,17 @@
*/
public class AppenderAttachableImpl<E> implements AppenderAttachable<E> {
- final private List<Appender<E>> appenderList = new ArrayList<Appender<E>>();
+ final private CopyOnWriteArrayList<Appender<E>> appenderList = new CopyOnWriteArrayList<Appender<E>>();
/**
* Attach an appender. If the appender is already in the list in won't be
* added again.
*/
public void addAppender(Appender<E> newAppender) {
- // Null values for newAppender parameter are strictly forbidden.
if (newAppender == null) {
- throw new IllegalArgumentException("Cannot null as an appener");
- }
- if (!appenderList.contains(newAppender)) {
- appenderList.add(newAppender);
+ throw new IllegalArgumentException("Null argument disallowed");
}
+ appenderList.addIfAbsent(newAppender);
}
/**
@@ -43,12 +39,9 @@
*/
public int appendLoopOnAppenders(E e) {
int size = 0;
- Appender<E> appender;
-
- size = appenderList.size();
- for (int i = 0; i < size; i++) {
- appender = (Appender<E>) appenderList.get(i);
+ for (Appender<E> appender : appenderList) {
appender.doAppend(e);
+ size++;
}
return size;
}
@@ -57,9 +50,9 @@
* Get all attached appenders as an Enumeration. If there are no attached
* appenders <code>null</code> is returned.
*
- * @return Enumeration An enumeration of attached appenders.
+ * @return Iterator An iterator of attached appenders.
*/
- public Iterator iteratorForAppenders() {
+ public Iterator<Appender<E>> iteratorForAppenders() {
return appenderList.iterator();
}
@@ -74,18 +67,11 @@
if (name == null) {
return null;
}
-
- int size = appenderList.size();
- Appender<E> appender;
-
- for (int i = 0; i < size; i++) {
- appender = appenderList.get(i);
-
+ for (Appender<E> appender : appenderList) {
if (name.equals(appender.getName())) {
return appender;
}
}
-
return null;
}
@@ -99,18 +85,11 @@
if (appender == null) {
return false;
}
-
- int size = appenderList.size();
- Appender a;
-
- for (int i = 0; i < size; i++) {
- a = (Appender) appenderList.get(i);
-
+ for (Appender<E> a : appenderList) {
if (a == appender) {
return true;
}
}
-
return false;
}
@@ -118,13 +97,9 @@
* Remove and stop all previously attached appenders.
*/
public void detachAndStopAllAppenders() {
- int len = appenderList.size();
-
- for (int i = 0; i < len; i++) {
- Appender a = (Appender) appenderList.get(i);
+ for (Appender<E> a : appenderList) {
a.stop();
}
-
appenderList.clear();
}
@@ -143,18 +118,15 @@
* Remove the appender with the name passed as parameter form the list of
* appenders.
*/
- public Appender<E> detachAppender(String name) {
+ public boolean detachAppender(String name) {
if (name == null) {
- return null;
+ return false;
}
-
- int size = appenderList.size();
-
- for (int i = 0; i < size; i++) {
- if (name.equals((appenderList.get(i)).getName())) {
- return appenderList.remove(i);
+ for (Appender<E> a : appenderList) {
+ if (name.equals((a).getName())) {
+ return appenderList.remove(a);
}
}
- return null;
+ return false;
}
}
Modified: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/AllCoreTest.java
==============================================================================
--- logback/trunk/logback-core/src/test/java/ch/qos/logback/core/AllCoreTest.java (original)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/AllCoreTest.java Mon Oct 20 20:51:02 2008
@@ -23,6 +23,7 @@
suite.addTest(ch.qos.logback.core.PackageTest.suite());
suite.addTest(ch.qos.logback.core.joran.PackageTest.suite());
suite.addTest(ch.qos.logback.core.appender.PackageTest.suite());
+ suite.addTest(ch.qos.logback.core.spi.PackageTest.suite());
suite.addTest(ch.qos.logback.core.rolling.PackageTest.suite());
return suite;
}
Added: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/spi/AppenderAttachableImplTest.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/spi/AppenderAttachableImplTest.java Mon Oct 20 20:51:02 2008
@@ -0,0 +1,177 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ *
+ * Copyright (C) 2000-2008, QOS.ch
+ *
+ * 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.
+ */
+package ch.qos.logback.core.spi;
+
+
+import static org.junit.Assert.*;
+import ch.qos.logback.core.appender.NOPAppender;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.layout.NopLayout;
+
+import java.util.Iterator;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * This test case verifies all the methods of AppenderAttableImpl work properly.
+ *
+ * @author Raplh Goers
+ */
+public class AppenderAttachableImplTest {
+
+
+ private AppenderAttachableImpl<TestEvent> aai;
+
+ @Before
+ public void setUp() throws Exception {
+ aai = new AppenderAttachableImpl<TestEvent>();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ aai = null;
+ }
+
+ @Test
+ public void testAddAppender() throws Exception {
+ TestEvent event = new TestEvent();
+ NOPAppender<TestEvent> ta = new NOPAppender<TestEvent>();
+ ta.setLayout(new NopLayout<TestEvent>());
+ ta.start();
+ aai.addAppender(ta);
+ ta = new NOPAppender<TestEvent>();
+ ta.setName("test");
+ ta.setLayout(new NopLayout<TestEvent>());
+ ta.start();
+ aai.addAppender(ta);
+ int size = aai.appendLoopOnAppenders(event);
+ assertTrue("Incorrect number of appenders", size == 2);
+ }
+
+ @Test
+ public void testIteratorForAppenders() throws Exception {
+ NOPAppender<TestEvent> ta = new NOPAppender<TestEvent>();
+ ta.setLayout(new NopLayout<TestEvent>());
+ ta.start();
+ aai.addAppender(ta);
+ NOPAppender<TestEvent> tab = new NOPAppender<TestEvent>();
+ tab.setName("test");
+ tab.setLayout(new NopLayout<TestEvent>());
+ tab.start();
+ aai.addAppender(tab);
+ Iterator<Appender<TestEvent>> iter = aai.iteratorForAppenders();
+ int size = 0;
+ while (iter.hasNext()) {
+ ++size;
+ Appender<TestEvent> app = iter.next();
+ assertTrue("Bad Appender", app == ta || app == tab);
+ }
+ assertTrue("Incorrect number of appenders", size == 2);
+ }
+
+ @Test
+ public void getGetAppender() throws Exception {
+ NOPAppender<TestEvent> test = new NOPAppender<TestEvent>();
+ test.setLayout(new NopLayout<TestEvent>());
+ test.setName("test");
+ test.start();
+ aai.addAppender(test);
+
+ NOPAppender<TestEvent> testOther = new NOPAppender<TestEvent>();
+ testOther.setName("testOther");
+ testOther.setLayout(new NopLayout<TestEvent>());
+ testOther.start();
+ aai.addAppender(testOther);
+
+ Appender a = aai.getAppender("testOther");
+ assertNotNull("Could not find appender", a);
+ assertTrue("Wrong appender", a == testOther);
+
+ a = aai.getAppender("test");
+ assertNotNull("Could not find appender", a);
+ assertTrue("Wrong appender", a == test);
+ a = aai.getAppender("NotThere");
+ assertNull("Appender was returned", a);
+ }
+
+ @Test
+ public void testIsAttached() throws Exception {
+ NOPAppender<TestEvent> ta = new NOPAppender<TestEvent>();
+ ta.setLayout(new NopLayout<TestEvent>());
+ ta.start();
+ aai.addAppender(ta);
+ NOPAppender<TestEvent> tab = new NOPAppender<TestEvent>();
+ tab.setName("test");
+ tab.setLayout(new NopLayout<TestEvent>());
+ tab.start();
+ aai.addAppender(tab);
+ assertTrue("Appender is not attached", aai.isAttached(ta));
+ assertTrue("Appender is not attached", aai.isAttached(tab));
+ }
+
+ @Test
+ public void testDetachAndStopAllAppenders() throws Exception {
+ NOPAppender<TestEvent> ta = new NOPAppender<TestEvent>();
+ ta.setLayout(new NopLayout<TestEvent>());
+ ta.start();
+ aai.addAppender(ta);
+ NOPAppender<TestEvent> tab = new NOPAppender<TestEvent>();
+ tab.setName("test");
+ tab.setLayout(new NopLayout<TestEvent>());
+ tab.start();
+ aai.addAppender(tab);
+ assertTrue("Appender was not started", tab.isStarted());
+ aai.detachAndStopAllAppenders();
+ assertNull("Appender was not removed", aai.getAppender("test"));
+ assertFalse("Appender was not stopped", tab.isStarted());
+ }
+
+ @Test
+ public void testDetachAppender() throws Exception {
+ NOPAppender<TestEvent> ta = new NOPAppender<TestEvent>();
+ ta.setLayout(new NopLayout<TestEvent>());
+ ta.start();
+ aai.addAppender(ta);
+ NOPAppender<TestEvent> tab = new NOPAppender<TestEvent>();
+ tab.setName("test");
+ tab.setLayout(new NopLayout<TestEvent>());
+ tab.start();
+ aai.addAppender(tab);
+ assertTrue("Appender not detached", aai.detachAppender(tab));
+ assertNull("Appender was not removed", aai.getAppender("test"));
+ assertFalse("Appender detach error", aai.detachAppender(tab));
+ }
+
+ @Test
+ public void testDetachAppenderByName() throws Exception {
+ NOPAppender<TestEvent> ta = new NOPAppender<TestEvent>();
+ ta.setName("test1");
+ ta.setLayout(new NopLayout<TestEvent>());
+ ta.start();
+ aai.addAppender(ta);
+ NOPAppender<TestEvent> tab = new NOPAppender<TestEvent>();
+ tab.setName("test");
+ tab.setLayout(new NopLayout<TestEvent>());
+ tab.start();
+ aai.addAppender(tab);
+
+ assertTrue(aai.detachAppender("test"));
+ assertTrue(aai.detachAppender("test1"));
+ assertFalse( aai.detachAppender("test1"));
+ }
+
+ private static class TestEvent {
+
+ }
+
+}
+
Added: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/spi/PackageTest.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/spi/PackageTest.java Mon Oct 20 20:51:02 2008
@@ -0,0 +1,24 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ *
+ * Copyright (C) 2000-2008, QOS.ch
+ *
+ * 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.
+ */
+package ch.qos.logback.core.spi;
+
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+public class PackageTest {
+ public static Test suite() {
+ TestSuite suite = new TestSuite();
+ suite.addTest(new JUnit4TestAdapter(AppenderAttachableImplTest.class));
+ return suite;
+ }
+
+}
More information about the logback-dev
mailing list