Index: logback-access/src/test/java/ch/qos/logback/access/jetty/JettyBasicTest.java
===================================================================
--- logback-access/src/test/java/ch/qos/logback/access/jetty/JettyBasicTest.java (revision 1828)
+++ logback-access/src/test/java/ch/qos/logback/access/jetty/JettyBasicTest.java (working copy)
@@ -59,7 +59,7 @@
String result = Util.readToString(connection.getInputStream());
assertEquals("hello world", result);
- //Thread.sleep(100);
+ Thread.sleep(100);
ListAppender appender = (ListAppender) requestLogImpl.getAppender("list");
assertTrue(appender.list.size()>0);
AccessEvent event = (AccessEvent) appender.list.get(0);
Index: logback-classic/src/main/java/ch/qos/logback/classic/Logger.java
===================================================================
--- logback-classic/src/main/java/ch/qos/logback/classic/Logger.java (revision 1828)
+++ logback-classic/src/main/java/ch/qos/logback/classic/Logger.java (working copy)
@@ -196,9 +196,7 @@
// propagate the parent levelInt change to this logger's children
// propagate the parent levelInt change to this logger's children
if (childrenList != null) {
- int len = childrenList.size();
- for (int i = 0; i < len; i++) {
- Logger child = (Logger) childrenList.get(i);
+ for (Logger child : childrenList) {
child.handleParentLevelChange(newParentLevel);
}
}
@@ -209,22 +207,24 @@
* Remove all previously added appenders from this logger instance.
This
* is useful when re-reading configuration information.
*/
- public synchronized void detachAndStopAllAppenders() {
+ public void detachAndStopAllAppenders() {
if (aai != null) {
aai.detachAndStopAllAppenders();
}
}
- public synchronized Appender detachAppender(String name) {
+ public Appender detachAppender(String name) {
if (aai == null) {
return null;
}
return aai.detachAppender(name);
}
- public synchronized void addAppender(Appender newAppender) {
- if (aai == null) {
- aai = new AppenderAttachableImpl();
+ public void addAppender(Appender newAppender) {
+ synchronized(this) {
+ if (aai == null) {
+ aai = new AppenderAttachableImpl();
+ }
}
aai.addAppender(newAppender);
}
@@ -236,7 +236,7 @@
return aai.isAttached(appender);
}
- public synchronized Iterator iteratorForAppenders() {
+ public Iterator iteratorForAppenders() {
if (aai == null) {
return Collections.EMPTY_LIST.iterator();
}
@@ -287,7 +287,7 @@
/**
* 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;
}
Index: logback-core/src/test/java/ch/qos/logback/core/AllCoreTest.java
===================================================================
--- logback-core/src/test/java/ch/qos/logback/core/AllCoreTest.java (revision 1828)
+++ logback-core/src/test/java/ch/qos/logback/core/AllCoreTest.java (working copy)
@@ -23,6 +23,7 @@
suite.addTest(ch.qos.logback.core.joran.PackageTest.suite());
suite.addTest(ch.qos.logback.core.appender.PackageTest.suite());
suite.addTest(ch.qos.logback.core.rolling.PackageTest.suite());
+ suite.addTest(ch.qos.logback.core.spi.PackageTest.suite());
return suite;
}
}
Index: logback-core/src/test/java/ch/qos/logback/core/spi/AppenderAttachableImplTest.java
===================================================================
--- logback-core/src/test/java/ch/qos/logback/core/spi/AppenderAttachableImplTest.java (revision 0)
+++ logback-core/src/test/java/ch/qos/logback/core/spi/AppenderAttachableImplTest.java (revision 0)
@@ -0,0 +1,185 @@
+package ch.qos.logback.core.spi;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import ch.qos.logback.core.ConsoleAppender;
+import ch.qos.logback.core.AppenderBase;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.appender.NOPAppender;
+import ch.qos.logback.core.layout.NopLayout;
+
+import java.util.Iterator;
+
+/**
+ * This test case verifies all the methods of AppenderAttableImpl work properly.
+ *
+ * @author Ceki
+ */
+public class AppenderAttachableImplTest extends TestCase {
+ /**
+ * To run test suite from command line.
+ */
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ /**
+ * Set up a test suite.
+ */
+ public static Test suite() {
+ return new TestSuite(AppenderAttachableImplTest.class);
+ }
+
+ public AppenderAttachableImplTest(String testName) {
+ super(testName);
+ }
+
+ private AppenderAttachableImpl at;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ at = new AppenderAttachableImpl();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ at = null;
+ }
+
+ public void testAddAppender() throws Exception {
+ TestEvent event = new TestEvent();
+ TestAppender ta = new TestAppender();
+ ta.setLayout(new NopLayout());
+ ta.start();
+ at.addAppender(ta);
+ ta = new TestAppender();
+ ta.setLayout(new NopLayout());
+ ta.setName("test");
+ ta.start();
+ at.addAppender(ta);
+ int size = at.appendLoopOnAppenders(event);
+ assertTrue("Incorrect number of appenders", size == 2);
+ }
+
+ public void testIteratorForAppenders() throws Exception {
+ TestAppender ta = new TestAppender();
+ ta.setLayout(new NopLayout());
+ ta.start();
+ at.addAppender(ta);
+ TestAppender tab = new TestAppender();
+ tab.setLayout(new NopLayout());
+ tab.setName("test");
+ tab.start();
+ at.addAppender(tab);
+ Iterator> iter = at.iteratorForAppenders();
+ int size = 0;
+ while (iter.hasNext()) {
+ ++size;
+ TestAppender app = iter.next();
+ assertTrue("Bad Appender", app == ta || app == tab);
+ }
+ assertTrue("Incorrect number of appenders", size == 2);
+ }
+
+ public void getGetAppender() throws Exception {
+ TestAppender ta = new TestAppender();
+ ta.setLayout(new NopLayout());
+ ta.start();
+ at.addAppender(ta);
+ ta.setName("test1");
+ TestAppender tab = new TestAppender();
+ tab.setLayout(new NopLayout());
+ tab.setName("test");
+ tab.start();
+ at.addAppender(tab);
+ Appender a = at.getAppender("test");
+ assertNotNull("Could not find appender", a);
+ assertTrue("Wrong appender", a == tab);
+ a = at.getAppender("test1");
+ assertNotNull("Could not find appender", a);
+ assertTrue("Wrong appender", a == ta);
+ a = at.getAppender("NotThere");
+ assertNull("Appender was returned", a);
+ }
+
+ public void testIsAttached() throws Exception {
+ TestAppender ta = new TestAppender();
+ ta.setLayout(new NopLayout());
+ ta.start();
+ at.addAppender(ta);
+ ta.setName("test1");
+ TestAppender tab = new TestAppender();
+ tab.setLayout(new NopLayout());
+ tab.setName("test");
+ tab.start();
+ at.addAppender(tab);
+ assertTrue("Appender is not attached", at.isAttached(ta));
+ assertTrue("Appender is not attached", at.isAttached(tab));
+ }
+
+ public void testDetachAndStopAllAppenders() throws Exception {
+ TestAppender ta = new TestAppender();
+ ta.setLayout(new NopLayout());
+ ta.start();
+ at.addAppender(ta);
+ ta.setName("test1");
+ TestAppender tab = new TestAppender();
+ tab.setLayout(new NopLayout());
+ tab.setName("test");
+ tab.start();
+ at.addAppender(tab);
+ assertTrue("Appender was not started", tab.isStarted());
+ at.detachAndStopAllAppenders();
+ assertNull("Appender was not removed", at.getAppender("test"));
+ assertFalse("Appender was not stopped", tab.isStarted());
+ }
+
+ public void testDetachAppender() throws Exception {
+ TestAppender ta = new TestAppender();
+ ta.setLayout(new NopLayout());
+ ta.start();
+ at.addAppender(ta);
+ ta.setName("test1");
+ TestAppender tab = new TestAppender();
+ tab.setLayout(new NopLayout());
+ tab.setName("test");
+ tab.start();
+ at.addAppender(tab);
+ assertTrue("Appender not detached", at.detachAppender(tab));
+ assertNull("Appender was not removed", at.getAppender("test"));
+ assertFalse("Appender detach error", at.detachAppender(tab));
+ }
+
+ public void testDetachAppenderByName() throws Exception {
+ TestAppender ta = new TestAppender();
+ ta.setLayout(new NopLayout());
+ ta.start();
+ at.addAppender(ta);
+ ta.setName("test1");
+ TestAppender tab = new TestAppender();
+ tab.setLayout(new NopLayout());
+ tab.setName("test");
+ tab.start();
+ at.addAppender(tab);
+ Appender a = at.detachAppender("test");
+ assertNotNull("Appender not detached", a);
+ a = at.detachAppender("test1");
+ assertNotNull("Appender not detached", a);
+ a = at.detachAppender("test1");
+ assertNull("Appender detach error", a);
+ }
+
+ private static class TestEvent {
+
+ }
+
+
+ private static class TestAppender extends AppenderBase {
+
+ protected void append(TestEvent event) {
+
+ }
+
+ }
+}
\ No newline at end of file
Index: logback-core/src/test/java/ch/qos/logback/core/spi/PackageTest.java
===================================================================
--- logback-core/src/test/java/ch/qos/logback/core/spi/PackageTest.java (revision 0)
+++ logback-core/src/test/java/ch/qos/logback/core/spi/PackageTest.java (revision 0)
@@ -0,0 +1,15 @@
+package ch.qos.logback.core.spi;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+public class PackageTest extends TestCase {
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite();
+ suite.addTestSuite(AppenderAttachableImplTest.class);
+ return suite;
+ }
+}
Index: logback-core/src/main/java/ch/qos/logback/core/spi/AppenderAttachableImpl.java
===================================================================
--- logback-core/src/main/java/ch/qos/logback/core/spi/AppenderAttachableImpl.java (revision 1828)
+++ logback-core/src/main/java/ch/qos/logback/core/spi/AppenderAttachableImpl.java (working copy)
@@ -9,20 +9,29 @@
*/
package ch.qos.logback.core.spi;
-import java.util.ArrayList;
import java.util.Iterator;
-import java.util.List;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
import ch.qos.logback.core.Appender;
/**
- * A straightforward implementation of the {@link AppenderAttachable} interface.
+ * An implementation of the {@link AppenderAttachable} interface. This implementation would be
+ * much simpler if the name attribute of the Appender interface was required and was immutable.
+ * Since the name is not required to be set and might be changed or set after attaching it, this
+ * class must account for those rare occurances.
*
* @author Ceki Gülcü
*/
public class AppenderAttachableImpl implements AppenderAttachable {
- final private List> appenderList = new ArrayList>();
+ private final ConcurrentMap> appenders =
+ new ConcurrentHashMap>();
+ private AtomicLong counter = new AtomicLong();
+ private static final String APPENDER_NAME_ROOT = "__APPENDER__:";
/**
* Attach an appender. If the appender is already in the list in won't be
@@ -33,21 +42,21 @@
if (newAppender == null) {
throw new IllegalArgumentException("Cannot null as an appener");
}
- if (!appenderList.contains(newAppender)) {
- appenderList.add(newAppender);
+ String name = newAppender.getName();
+ if (name == null)
+ {
+ name = APPENDER_NAME_ROOT + counter.getAndIncrement();
}
+ appenders.putIfAbsent(name, newAppender);
}
/**
* Call the doAppend
method on all attached appenders.
*/
public int appendLoopOnAppenders(E e) {
- int size = 0;
- Appender appender;
-
- size = appenderList.size();
- for (int i = 0; i < size; i++) {
- appender = (Appender) appenderList.get(i);
+ Collection> coll = appenders.values();
+ int size = coll.size();
+ for (Appender appender : coll) {
appender.doAppend(e);
}
return size;
@@ -60,7 +69,7 @@
* @return Enumeration An enumeration of attached appenders.
*/
public Iterator iteratorForAppenders() {
- return appenderList.iterator();
+ return appenders.values().iterator();
}
/**
@@ -74,15 +83,13 @@
if (name == null) {
return null;
}
-
- int size = appenderList.size();
- Appender appender;
-
- for (int i = 0; i < size; i++) {
- appender = appenderList.get(i);
-
- if (name.equals(appender.getName())) {
- return appender;
+ Appender appender = appenders.get(name);
+ if (appender != null) {
+ return appender;
+ }
+ for (Appender a : appenders.values()) {
+ if (name.equals(a.getName())) {
+ return a;
}
}
@@ -100,17 +107,18 @@
return false;
}
- int size = appenderList.size();
- Appender a;
-
- for (int i = 0; i < size; i++) {
- a = (Appender) appenderList.get(i);
-
+ String name = appender.getName();
+ if (name != null) {
+ Appender a = appenders.get(name);
+ if (a != null && a == appender) {
+ return true;
+ }
+ }
+ for (Appender a : appenders.values()) {
if (a == appender) {
return true;
}
}
-
return false;
}
@@ -118,14 +126,10 @@
* 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);
- a.stop();
+ for (Map.Entry> entry : appenders.entrySet()) {
+ entry.getValue().stop();
+ appenders.remove(entry.getKey(), entry.getValue());
}
-
- appenderList.clear();
}
/**
@@ -136,7 +140,16 @@
if (appender == null) {
return false;
}
- return appenderList.remove(appender);
+ String name = appender.getName();
+ if (appenders.containsKey(name)) {
+ return appenders.remove(name, appender);
+ }
+ for (Map.Entry> entry : appenders.entrySet()) {
+ if (appender == entry.getValue()) {
+ return appenders.remove(entry.getKey(), appender);
+ }
+ }
+ return false;
}
/**
@@ -147,12 +160,13 @@
if (name == null) {
return null;
}
-
- int size = appenderList.size();
-
- for (int i = 0; i < size; i++) {
- if (name.equals((appenderList.get(i)).getName())) {
- return appenderList.remove(i);
+ Appender a = appenders.remove(name);
+ if (a != null) {
+ return a;
+ }
+ for (Map.Entry> entry : appenders.entrySet()) {
+ if (name.equals(entry.getValue().getName())) {
+ return appenders.remove(entry.getKey());
}
}
return null;