### Eclipse Workspace Patch 1.0
#P log4j2
Index: api/src/main/java/org/apache/logging/log4j/ThreadContext.java
===================================================================
--- api/src/main/java/org/apache/logging/log4j/ThreadContext.java (revision 1439358)
+++ api/src/main/java/org/apache/logging/log4j/ThreadContext.java (working copy)
@@ -17,6 +17,15 @@
package org.apache.logging.log4j;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.spi.DefaultThreadContextMap;
import org.apache.logging.log4j.spi.LoggerContextFactory;
@@ -26,15 +35,6 @@
import org.apache.logging.log4j.util.PropertiesUtil;
import org.apache.logging.log4j.util.ProviderUtil;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-
/**
* The ThreadContext allows applications to store information either in a Map.
*
@@ -192,8 +192,9 @@
* @return An immutable copy of the ThreadContext Map.
*/
public static Map getImmutableContext() {
- final Map map = contextMap.get();
- return map == null ? new ImmutableMap() : new ImmutableMap(map);
+ // delegate to ThreadContextMap: the implementing class may have a
+ // very efficient way to create an immutable copy
+ return contextMap.getImmutableContext();
}
/**
@@ -217,7 +218,7 @@
*/
public static ContextStack cloneStack() {
final ContextStack stack = localStack.get();
- return stack == null ? new ThreadContextStack() : new ThreadContextStack(stack.asList());
+ return stack == null ? new ThreadContextStack() : stack.copy();
}
/**
@@ -226,6 +227,8 @@
*/
public static ContextStack getImmutableStack() {
final ContextStack stack = localStack.get();
+
+ // here we use the constructor that makes a shallow copy of the stack
return stack == null ? EMPTY_STACK : new ImmutableStack(stack.asList());
}
@@ -237,6 +240,7 @@
if (stack.size() == 0 || !useStack) {
return;
}
+ // use the constructor that makes a deep copy of the selection
localStack.set(new ThreadContextStack(stack));
}
@@ -264,7 +268,10 @@
if (s == null || s.getDepth() == 0) {
return "";
}
- return s.pop();
+ final ContextStack copy = s.copy(); // copy on write
+ final String result = copy.pop();
+ localStack.set(copy);
+ return result;
}
/**
@@ -296,13 +303,17 @@
if (!useStack) {
return;
}
- ContextStack stack = localStack.get();
- if (stack == null) {
- stack = new ThreadContextStack();
- localStack.set(stack);
- }
- stack.push(message);
+ final ContextStack stack = localStack.get();
+ ContextStack copy = null; // copy on write
+ if (stack == null) {
+ copy = new ThreadContextStack();
+ } else {
+ copy = stack.copy();
+ }
+ copy.push(message);
+ localStack.set(copy);
}
+
/**
* Push new diagnostic context information for the current thread.
*
@@ -318,12 +329,7 @@
if (!useStack) {
return;
}
- ContextStack stack = localStack.get();
- if (stack == null) {
- stack = new ThreadContextStack();
- localStack.set(stack);
- }
- stack.push(ParameterizedMessage.format(message, args));
+ push(ParameterizedMessage.format(message, args));
}
/**
@@ -380,7 +386,9 @@
public static void trim(final int depth) {
final ContextStack stack = localStack.get();
if (stack != null) {
- stack.trim(depth);
+ final ContextStack copy = stack.copy(); // copy on write
+ copy.trim(depth);
+ localStack.set(copy);
}
}
@@ -441,63 +449,85 @@
/**
* The ContextStack implementation.
*/
- private static class ThreadContextStack extends ArrayList implements ContextStack {
+ private static class ThreadContextStack implements ContextStack {
- private static final long serialVersionUID = 5050501L;
+ private static final long serialVersionUID = 5050501L;
- public ThreadContextStack() {
- super();
- }
+ private List list;
- public ThreadContextStack(final Collection collection) {
- super(collection);
- }
+ public ThreadContextStack() {
+ list = new ArrayList();
+ }
- public String pop() {
- final int index = size() - 1;
- if (index >= 0) {
- final String result = get(index);
- remove(index);
- return result;
- }
- throw new NoSuchElementException("The ThreadContext stack is empty");
- }
+ /**
+ * This constructor uses the specified list as its internal data
+ * structure unchanged. It does not make a defensive copy.
+ */
+ public ThreadContextStack(List aList) {
+ list = aList; // don't copy!
+ }
- public String peek() {
- final int index = size() - 1;
- if (index >= 0) {
- return get(index);
- }
- return null;
- }
+ /**
+ * This constructor copies the elements of the specified collection into
+ * a new list. Changes to the specified collection will not affect this
+ * {@code ThreadContextStack}.
+ */
+ public ThreadContextStack(Collection collection) {
+ list = new ArrayList(collection);
+ }
- public void push(final String message) {
- add(message);
- }
+ public void clear() {
+ list.clear();
+ }
- public int getDepth() {
- return size();
- }
+ public String pop() {
+ int index = list.size() - 1;
+ if (index >= 0) {
+ String result = list.get(index);
+ list.remove(index);
+ return result;
+ }
+ throw new NoSuchElementException("The ThreadContext stack is empty");
+ }
- public List asList() {
- return this;
- }
+ public String peek() {
+ int index = list.size() - 1;
+ if (index >= 0) {
+ return list.get(index);
+ }
+ return null;
+ }
- public void trim(final int depth) {
- if (depth < 0) {
- throw new IllegalArgumentException("Maximum stack depth cannot be negative");
- }
- while (size() > depth) {
- remove(size() - 1);
- }
+ public void push(String message) {
+ list.add(message);
+ }
- }
+ public int getDepth() {
+ return list.size();
+ }
- public ContextStack copy() {
- return new ThreadContextStack(this);
- }
+ public List asList() {
+ return list;
+ }
+
+ public void trim(int depth) {
+ if (depth < 0) {
+ throw new IllegalArgumentException(
+ "Maximum stack depth cannot be negative");
+ }
+ while (list.size() > depth) {
+ list.remove(list.size() - 1);
+ }
+ }
+
+ /**
+ * Returns a deep copy of this stack.
+ */
+ public ContextStack copy() {
+ return new ThreadContextStack(new ArrayList(list));
+ }
}
-
+
/**
* An immutable ContextStack.
*/
@@ -508,21 +538,21 @@
public ImmutableStack() {
}
- public ImmutableStack(final Collection collection) {
+ public ImmutableStack(Collection collection) {
super(collection);
}
- public ImmutableStack(final ThreadContextStack stack) {
- super(stack);
+ public ImmutableStack(ThreadContextStack stack) {
+ super(stack.list);
}
@Override
- public void push(final String message) {
+ public void push(String message) {
throw new UnsupportedOperationException("Stack cannot be modified");
}
@Override
- public void trim(final int depth) {
+ public void trim(int depth) {
throw new UnsupportedOperationException("Stack cannot be modified");
}
}